Skip to content

Commit 171c19b

Browse files
authored
Merge branch '4.22' into ghi11941-restoreWithPassword
2 parents 7746aa9 + 7ea1dca commit 171c19b

422 files changed

Lines changed: 9807 additions & 2180 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ jobs:
282282
# https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md#mysql
283283
sudo apt-get install -y mysql-server
284284
sudo systemctl start mysql
285-
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY ''; FLUSH PRIVILEGES;"
285+
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY ''; FLUSH PRIVILEGES;"
286286
sudo systemctl restart mysql
287287
sudo mysql -uroot -e "SELECT VERSION();"
288288

agent/conf/agent.properties

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,4 +472,3 @@ iscsi.session.cleanup.enabled=false
472472
# Optional vCenter SHA1 thumbprint for VMware to KVM conversion via VDDK, passed as
473473
# -io vddk-thumbprint=<value>. If unset, CloudStack computes it on the KVM host via openssl.
474474
#vddk.thumbprint=
475-

agent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<parent>
2525
<groupId>org.apache.cloudstack</groupId>
2626
<artifactId>cloudstack</artifactId>
27-
<version>4.22.1.0-SNAPSHOT</version>
27+
<version>4.22.2.0-SNAPSHOT</version>
2828
</parent>
2929
<dependencies>
3030
<dependency>

api/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<parent>
2525
<groupId>org.apache.cloudstack</groupId>
2626
<artifactId>cloudstack</artifactId>
27-
<version>4.22.1.0-SNAPSHOT</version>
27+
<version>4.22.2.0-SNAPSHOT</version>
2828
</parent>
2929
<dependencies>
3030
<dependency>

api/src/main/java/com/cloud/ha/Investigator.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@ public interface Investigator extends Adapter {
2626
* Returns if the vm is still alive.
2727
*
2828
* @param vm to work on.
29+
* @return true if vm is alive, otherwise false
2930
*/
30-
public boolean isVmAlive(VirtualMachine vm, Host host) throws UnknownVM;
31+
boolean isVmAlive(VirtualMachine vm, Host host) throws UnknownVM;
3132

32-
public Status isAgentAlive(Host agent);
33+
/**
34+
* Returns the agent status of the host.
35+
*
36+
* @param host
37+
* @return status of the host agent
38+
*/
39+
Status getHostAgentStatus(Host host);
3340

3441
class UnknownVM extends Exception {
35-
36-
/**
37-
*
38-
*/
3942
private static final long serialVersionUID = 1L;
40-
4143
};
4244
}

api/src/main/java/org/apache/cloudstack/acl/APIChecker.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,22 @@
1717
package org.apache.cloudstack.acl;
1818

1919
import com.cloud.exception.PermissionDeniedException;
20+
import com.cloud.exception.RequestLimitException;
2021
import com.cloud.user.Account;
2122
import com.cloud.user.User;
2223
import com.cloud.utils.component.Adapter;
2324

25+
import java.util.ArrayList;
2426
import java.util.List;
2527

28+
import org.apache.logging.log4j.LogManager;
29+
import org.apache.logging.log4j.Logger;
30+
2631
/**
2732
* APICheckers is designed to verify the ownership of resources and to control the access to APIs.
2833
*/
2934
public interface APIChecker extends Adapter {
35+
Logger LOGGER = LogManager.getLogger(APIChecker.class);
3036
// Interface for checking access for a role using apiname
3137
// If true, apiChecker has checked the operation
3238
// If false, apiChecker is unable to handle the operation or not implemented
@@ -42,5 +48,27 @@ public interface APIChecker extends Adapter {
4248
* @return the list of allowed apis for the given user
4349
*/
4450
List<String> getApisAllowedToUser(Role role, User user, List<String> apiNames) throws PermissionDeniedException;
51+
52+
default List<String> getApisAllowedToAccount(Account account, List<String> apiNames) {
53+
List<String> allowedApis = new ArrayList<>();
54+
for (String apiName : apiNames) {
55+
try {
56+
checkAccess(account, apiName);
57+
allowedApis.add(apiName);
58+
} catch (RequestLimitException e) {
59+
// Non-ACL failure (e.g. rate limiting) should not be treated as simple "not allowed".
60+
// Propagate as unchecked so callers are aware of the failure.
61+
throw new RuntimeException("Failed to check access for API [" + apiName + "] due to request limits", e);
62+
} catch (PermissionDeniedException e) {
63+
LOGGER.trace("Account [" + account + "] is not allowed to access API [" + apiName + "]");
64+
}
65+
}
66+
return allowedApis;
67+
}
68+
4569
boolean isEnabled();
70+
71+
default void refreshRoleCacheOnPermissionsChange(Role role) {
72+
// Only applicable for dynamic role based checkers
73+
}
4674
}

api/src/main/java/org/apache/cloudstack/acl/Rule.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,18 @@
2525

2626
public final class Rule {
2727
private final String rule;
28+
private final Pattern compiledPattern;
2829
private final static Pattern ALLOWED_PATTERN = Pattern.compile("^[a-zA-Z0-9*]+$");
2930

3031
public Rule(final String rule) {
3132
validate(rule);
3233
this.rule = rule;
34+
this.compiledPattern = Pattern.compile(rule.replace("*", "\\w*"), Pattern.CASE_INSENSITIVE);
3335
}
3436

3537
public boolean matches(final String commandName) {
3638
return StringUtils.isNotEmpty(commandName)
37-
&& commandName.toLowerCase().matches(rule.toLowerCase().replace("*", "\\w*"));
39+
&& compiledPattern.matcher(commandName).matches();
3840
}
3941

4042
public String getRuleString() {

api/src/main/java/org/apache/cloudstack/api/ApiArgValidator.java

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@
1717

1818
package org.apache.cloudstack.api;
1919

20+
import java.util.Locale;
21+
import java.util.regex.Pattern;
22+
23+
import org.apache.commons.lang3.StringUtils;
24+
25+
import com.cloud.exception.InvalidParameterValueException;
26+
import com.cloud.utils.UuidUtils;
27+
2028
public enum ApiArgValidator {
2129
/**
22-
* Validates if the parameter is null or empty with the method {@link Strings#isNullOrEmpty(String)}.
30+
* Validates if the parameter is null or empty with the method {@link StringUtils#isEmpty(CharSequence)}.
31+
* Validation is currently done in the method ParamProcessWorker#validateNonEmptyString(String, String).
2332
*/
2433
NotNullOrEmpty,
2534

@@ -29,12 +38,72 @@ public enum ApiArgValidator {
2938
PositiveNumber,
3039

3140
/**
32-
* Validates if the parameter is an UUID with the method {@link UuidUtils#isUuid(String)}.
41+
* Validates if the parameter is a UUID with the method {@link UuidUtils#isUuid(String)}.
42+
* Validation is currently done in the method ParamProcessWorker#validateUuidString(String, String).
3343
*/
3444
UuidString,
3545

3646
/**
3747
* Validates if the parameter is a valid RFC Compliance domain name.
3848
*/
3949
RFCComplianceDomainName,
50+
51+
/**
52+
* Validates command option strings to avoid unsafe/code-like content.
53+
*/
54+
SafeCommandOptions((param, annotation) -> {
55+
if (BaseCmd.CommandType.STRING.equals(annotation.type())) {
56+
validateSafeCommandOptions(param, annotation.name());
57+
}
58+
});
59+
60+
private static final Pattern SAFE_COMMAND_OPTIONS_PATTERN = Pattern.compile("^[A-Za-z0-9,._=:/+\\-\\s]*$");
61+
62+
private static final String[] UNSAFE_TOKENS = {
63+
"$(", "`", "&&", "||", ";", "|", ">", "<"
64+
};
65+
66+
private final ValidationRule rule;
67+
68+
ApiArgValidator() {
69+
this(null);
70+
}
71+
72+
ApiArgValidator(ValidationRule rule) {
73+
this.rule = rule;
74+
}
75+
76+
public void validate(final Object paramObj, final Parameter annotation) {
77+
if (rule != null) {
78+
rule.validate(paramObj, annotation);
79+
}
80+
}
81+
82+
private static void validateSafeCommandOptions(final Object param, final String argName) {
83+
final String value = String.valueOf(param);
84+
if (StringUtils.isBlank(value)) {
85+
return;
86+
}
87+
88+
if (!SAFE_COMMAND_OPTIONS_PATTERN.matcher(value).matches()) {
89+
throwInvalidParameterValueException(argName, "contains unsupported or unsafe characters");
90+
}
91+
92+
final String normalized = value.toLowerCase(Locale.ROOT);
93+
for (String token : UNSAFE_TOKENS) {
94+
if (normalized.contains(token)) {
95+
throwInvalidParameterValueException(argName, "contains code-like or unsafe content");
96+
}
97+
}
98+
}
99+
100+
private static void throwInvalidParameterValueException(final String argName, final String customMsg) {
101+
throw new InvalidParameterValueException(String.format("Invalid value provided for API arg: %s%s", argName,
102+
StringUtils.isBlank(customMsg) ? "" : " - " + customMsg));
103+
}
104+
105+
@FunctionalInterface
106+
interface ValidationRule {
107+
void validate(Object paramObj, Parameter annotation);
108+
}
40109
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,7 @@ public String toString() {
14081408
}
14091409

14101410
public enum HostDetails {
1411-
all, capacity, events, stats, min;
1411+
all, capacity, core, events, stats, min;
14121412
}
14131413

14141414
public enum VMDetails {

api/src/main/java/org/apache/cloudstack/api/command/admin/ha/ConfigureHAForHostCmd.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ private void setupResponse(final boolean result, final String resourceUuid) {
8787
final HostHAResponse response = new HostHAResponse();
8888
response.setId(resourceUuid);
8989
response.setProvider(getHaProvider().toLowerCase());
90+
response.setStatus(result);
9091
response.setResponseName(getCommandName());
9192
setResponseObject(response);
9293
}

0 commit comments

Comments
 (0)