Skip to content

Commit d776534

Browse files
committed
Merge branch '4.19' into 4.20
2 parents 207a2c1 + 8c9216d commit d776534

File tree

21 files changed

+295
-98
lines changed

21 files changed

+295
-98
lines changed

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5240,10 +5240,9 @@ public Outcome<VirtualMachine> migrateVmAwayThroughJobQueue(final String vmUuid,
52405240
workJob = newVmWorkJobAndInfo.first();
52415241
VmWorkMigrateAway workInfo = new VmWorkMigrateAway(newVmWorkJobAndInfo.second(), srcHostId);
52425242

5243-
workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo));
5243+
setCmdInfoAndSubmitAsyncJob(workJob, workInfo, vmId);
52445244
}
52455245

5246-
_jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vmId);
52475246

52485247
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId());
52495248

engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ public void setRemoved(Date removed) {
503503

504504
@Override
505505
public String toString() {
506-
return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type"));
506+
return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type", "state"));
507507
}
508508

509509
@Override

plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ public class ListAndSwitchSAMLAccountCmd extends BaseCmd implements APIAuthentic
8181
//////////////// API parameters /////////////////////
8282
/////////////////////////////////////////////////////
8383

84-
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, required = false, description = "User uuid")
84+
@Parameter(name = ApiConstants.USER_ID, type = CommandType.UUID, entityType = UserResponse.class, description = "User uuid")
8585
private Long userId;
8686

87-
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, required = false, description = "Domain uuid")
87+
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Domain uuid")
8888
private Long domainId;
8989

9090
@Override
@@ -131,10 +131,12 @@ public String authenticate(final String command, final Map<String, Object[]> par
131131
}
132132

133133
if (userUuid != null && domainUuid != null) {
134+
logger.debug("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserAccount.getId() + "] to useraccount [" + userUuid + "] in domain [" + domainUuid + "]");
134135
final User user = _userDao.findByUuid(userUuid);
135136
final Domain domain = _domainDao.findByUuid(domainUuid);
136137
final UserAccount nextUserAccount = _accountService.getUserAccountById(user.getId());
137138
if (nextUserAccount != null && !nextUserAccount.getAccountState().equals(Account.State.ENABLED.toString())) {
139+
logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account [" + nextUserAccount.getAccountName() + "] is not enabled");
138140
throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(),
139141
"The requested user account is locked and cannot be switched to, please contact your administrator.",
140142
params, responseType));
@@ -145,25 +147,31 @@ public String authenticate(final String command, final Map<String, Object[]> par
145147
|| !nextUserAccount.getExternalEntity().equals(currentUserAccount.getExternalEntity())
146148
|| (nextUserAccount.getDomainId() != domain.getId())
147149
|| (nextUserAccount.getSource() != User.Source.SAML2)) {
150+
logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account is not found or invalid");
148151
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(),
149152
"User account is not allowed to switch to the requested account",
150153
params, responseType));
151154
}
152155
try {
153156
if (_apiServer.verifyUser(nextUserAccount.getId())) {
157+
logger.info("User [" + currentUserAccount.getUsername() + "] user profile switch is accepted: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]");
158+
// need to set a sessoin variable to inform the login function of the specific user to login as, rather than using email only (which could have multiple matches)
159+
session.setAttribute("nextUserId", user.getId());
154160
final LoginCmdResponse loginResponse = (LoginCmdResponse) _apiServer.loginUser(session, nextUserAccount.getUsername(), nextUserAccount.getUsername() + nextUserAccount.getSource().toString(),
155161
nextUserAccount.getDomainId(), null, remoteAddress, params);
156162
SAMLUtils.setupSamlUserCookies(loginResponse, resp);
157-
resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value());
163+
session.removeAttribute("nextUserId");
164+
logger.debug("User [" + currentUserAccount.getUsername() + "] user profile switch cookies set: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]");
165+
//resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value());
158166
return ApiResponseSerializer.toSerializedString(loginResponse, responseType);
159167
}
160168
} catch (CloudAuthenticationException | IOException exception) {
161-
logger.debug("Failed to switch to request SAML user account due to: " + exception.getMessage());
169+
logger.debug("User [{}] user profile switch cookies set FAILED: from [{}] to user profile [{}] in domain [{}] with account [{}]", currentUserAccount.getUsername(), currentUserId, userUuid, domainUuid, nextUserAccount.getAccountName(), exception);
162170
}
163171
} else {
164172
List<UserAccountVO> switchableAccounts = _userAccountDao.getAllUsersByNameAndEntity(currentUserAccount.getUsername(), currentUserAccount.getExternalEntity());
165-
if (switchableAccounts != null && switchableAccounts.size() > 0 && currentUserId != User.UID_SYSTEM) {
166-
List<SamlUserAccountResponse> accountResponses = new ArrayList<SamlUserAccountResponse>();
173+
if (switchableAccounts != null && !switchableAccounts.isEmpty() && currentUserId != User.UID_SYSTEM) {
174+
List<SamlUserAccountResponse> accountResponses = new ArrayList<>();
167175
for (UserAccountVO userAccount: switchableAccounts) {
168176
User user = _userDao.getUser(userAccount.getId());
169177
Domain domain = _domainService.getDomain(userAccount.getDomainId());
@@ -176,8 +184,9 @@ public String authenticate(final String command, final Map<String, Object[]> par
176184
accountResponse.setAccountName(userAccount.getAccountName());
177185
accountResponse.setIdpId(user.getExternalEntity());
178186
accountResponses.add(accountResponse);
187+
logger.debug("Returning available useraccount for [{}]: UserUUID: [{}], DomainUUID: [{}], Account: [{}]", currentUserAccount.getUsername(), user.getUuid(), domain.getUuid(), userAccount.getAccountName());
179188
}
180-
ListResponse<SamlUserAccountResponse> response = new ListResponse<SamlUserAccountResponse>();
189+
ListResponse<SamlUserAccountResponse> response = new ListResponse<>();
181190
response.setResponses(accountResponses);
182191
response.setResponseName(getCommandName());
183192
return ApiResponseSerializer.toSerializedString(response, responseType);
@@ -196,7 +205,7 @@ public APIAuthenticationType getAPIType() {
196205
@Override
197206
public void setAuthenticators(List<PluggableAPIAuthenticator> authenticators) {
198207
for (PluggableAPIAuthenticator authManager: authenticators) {
199-
if (authManager != null && authManager instanceof SAML2AuthManager) {
208+
if (authManager instanceof SAML2AuthManager) {
200209
_samlAuthManager = (SAML2AuthManager) authManager;
201210
}
202211
}

plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
import com.cloud.user.dao.UserAccountDao;
7979
import com.cloud.utils.db.EntityManager;
8080

81-
@APICommand(name = "samlSso", description = "SP initiated SAML Single Sign On", requestHasSensitiveInfo = true, responseObject = LoginCmdResponse.class, entityType = {})
81+
@APICommand(name = "samlSso", description = "SP initiated SAML Single Sign On", responseObject = LoginCmdResponse.class)
8282
public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthenticator, Configurable {
8383
private static final String s_name = "loginresponse";
8484

@@ -97,7 +97,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
9797
@Inject
9898
private UserAccountDao userAccountDao;
9999

100-
protected static ConfigKey<String> saml2FailedLoginRedirectUrl = new ConfigKey<String>("Advanced", String.class, "saml2.failed.login.redirect.url", "",
100+
protected static ConfigKey<String> saml2FailedLoginRedirectUrl = new ConfigKey<>("Advanced", String.class, "saml2.failed.login.redirect.url", "",
101101
"The URL to redirect the SAML2 login failed message (the default vaulue is empty).", true);
102102

103103
SAML2AuthManager samlAuthManager;
@@ -190,7 +190,7 @@ public String authenticate(final String command, final Map<String, Object[]> par
190190
String authnId = SAMLUtils.generateSecureRandomId();
191191
samlAuthManager.saveToken(authnId, domainPath, idpMetadata.getEntityId());
192192
logger.debug("Sending SAMLRequest id=" + authnId);
193-
String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value());
193+
String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), SAML2AuthManager.SAMLRequirePasswordLogin.value());
194194
resp.sendRedirect(redirectUrl);
195195
return "";
196196
} if (params.containsKey("SAMLart")) {
@@ -207,7 +207,7 @@ public String authenticate(final String command, final Map<String, Object[]> par
207207
params, responseType));
208208
}
209209

210-
String username = null;
210+
String username;
211211
Issuer issuer = processedSAMLResponse.getIssuer();
212212
SAMLProviderMetadata spMetadata = samlAuthManager.getSPMetadata();
213213
SAMLProviderMetadata idpMetadata = samlAuthManager.getIdPMetadata(issuer.getValue());
@@ -273,7 +273,7 @@ public String authenticate(final String command, final Map<String, Object[]> par
273273
try {
274274
assertion = decrypter.decrypt(encryptedAssertion);
275275
} catch (DecryptionException e) {
276-
logger.warn("SAML EncryptedAssertion error: " + e.toString());
276+
logger.warn("SAML EncryptedAssertion error: " + e);
277277
}
278278
if (assertion == null) {
279279
continue;
@@ -310,7 +310,7 @@ public String authenticate(final String command, final Map<String, Object[]> par
310310

311311
UserAccount userAccount = null;
312312
List<UserAccountVO> possibleUserAccounts = userAccountDao.getAllUsersByNameAndEntity(username, issuer.getValue());
313-
if (possibleUserAccounts != null && possibleUserAccounts.size() > 0) {
313+
if (possibleUserAccounts != null && !possibleUserAccounts.isEmpty()) {
314314
// Log into the first enabled user account
315315
// Users can switch to other allowed accounts later
316316
for (UserAccountVO possibleUserAccount : possibleUserAccounts) {
@@ -370,7 +370,7 @@ public APIAuthenticationType getAPIType() {
370370
@Override
371371
public void setAuthenticators(List<PluggableAPIAuthenticator> authenticators) {
372372
for (PluggableAPIAuthenticator authManager: authenticators) {
373-
if (authManager != null && authManager instanceof SAML2AuthManager) {
373+
if (authManager instanceof SAML2AuthManager) {
374374
samlAuthManager = (SAML2AuthManager) authManager;
375375
}
376376
}

plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe
7979
ConfigKey<String> SAMLUserSessionKeyPathAttribute = new ConfigKey<String>("Advanced", String.class, "saml2.user.sessionkey.path", "",
8080
"The Path attribute of sessionkey cookie when SAML users have logged in. If not set, it will be set to the path of SAML redirection URL (saml2.redirect.url).", true);
8181

82+
ConfigKey<Boolean> SAMLRequirePasswordLogin = new ConfigKey<Boolean>("Advanced", Boolean.class, "saml2.require.password", "true",
83+
"When enabled SAML2 will validate that the SAML login was performed with a password. If disabled, other forms of authentication are allowed (two-factor, certificate, etc) on the SAML Authentication Provider", true);
84+
85+
8286
SAMLProviderMetadata getSPMetadata();
8387
SAMLProviderMetadata getIdPMetadata(String entityId);
8488
Collection<SAMLProviderMetadata> getAllIdPMetadata();

plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,6 @@ public ConfigKey<?>[] getConfigKeys() {
541541
SAMLCloudStackRedirectionUrl, SAMLUserAttributeName,
542542
SAMLIdentityProviderMetadataURL, SAMLDefaultIdentityProviderId,
543543
SAMLSignatureAlgorithm, SAMLAppendDomainSuffix, SAMLTimeout, SAMLCheckSignature,
544-
SAMLForceAuthn, SAMLUserSessionKeyPathAttribute};
544+
SAMLForceAuthn, SAMLUserSessionKeyPathAttribute, SAMLRequirePasswordLogin};
545545
}
546546
}

0 commit comments

Comments
 (0)