diff --git a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java index 5c6fc838b3a..66a590d9cf8 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java +++ b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianClient.java @@ -52,6 +52,7 @@ import com.cloud.utils.nio.TrustAllManager; import com.fasterxml.jackson.databind.ObjectMapper; public class CloudianClient { + private static final Logger LOG = Logger.getLogger(CloudianClient.class); private final HttpClient httpClient; @@ -120,7 +121,7 @@ public class CloudianClient { //////////////// Public APIs: User ///////////////////// //////////////////////////////////////////////////////// - public boolean addUser(final UserInfo user) { + public boolean addUser(final CloudianUser user) { try { final HttpResponse response = put("/user", user); return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; @@ -130,35 +131,35 @@ public class CloudianClient { return false; } - public UserInfo listUser(final String userId, final String groupId) { + public CloudianUser listUser(final String userId, final String groupId) { try { final HttpResponse response = get(String.format("/user?userId=%s&groupId=%s", userId, groupId)); final ObjectMapper mapper = new ObjectMapper(); if (response.getEntity() == null || response.getEntity().getContent() == null) { return null; } - return mapper.readValue(response.getEntity().getContent(), UserInfo.class); + return mapper.readValue(response.getEntity().getContent(), CloudianUser.class); } catch (final IOException e) { LOG.error("Failed to list Cloudian user due to:", e); } return null; } - public List listUsers(final String groupId) { + public List listUsers(final String groupId) { try { final HttpResponse response = get(String.format("/user/list?groupId=%s&userType=all&userStatus=active", groupId)); final ObjectMapper mapper = new ObjectMapper(); if (response.getEntity() == null || response.getEntity().getContent() == null) { - return null; + return new ArrayList<>(); } - return Arrays.asList(mapper.readValue(response.getEntity().getContent(), UserInfo[].class)); + return Arrays.asList(mapper.readValue(response.getEntity().getContent(), CloudianUser[].class)); } catch (final IOException e) { LOG.error("Failed to list Cloudian users due to:", e); } return new ArrayList<>(); } - public boolean updateUser(final UserInfo user) { + public boolean updateUser(final CloudianUser user) { try { final HttpResponse response = post("/user", user); return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; @@ -182,7 +183,7 @@ public class CloudianClient { //////////////// Public APIs: Group ///////////////////// ///////////////////////////////////////////////////////// - public boolean addGroup(final GroupInfo group) { + public boolean addGroup(final CloudianGroup group) { try { final HttpResponse response = put("/group", group); return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; @@ -192,35 +193,35 @@ public class CloudianClient { return false; } - public GroupInfo listGroup(final String groupId) { + public CloudianGroup listGroup(final String groupId) { try { final HttpResponse response = get(String.format("/group?groupId=%s", groupId)); final ObjectMapper mapper = new ObjectMapper(); if (response.getEntity() == null || response.getEntity().getContent() == null) { return null; } - return mapper.readValue(response.getEntity().getContent(), GroupInfo.class); + return mapper.readValue(response.getEntity().getContent(), CloudianGroup.class); } catch (final IOException e) { LOG.error("Failed to list Cloudian group due to:", e); } return null; } - public List listGroups() { + public List listGroups() { try { final HttpResponse response = get("/group/list"); final ObjectMapper mapper = new ObjectMapper(); if (response.getEntity() == null || response.getEntity().getContent() == null) { - return null; + return new ArrayList<>(); } - return Arrays.asList(mapper.readValue(response.getEntity().getContent(), GroupInfo[].class)); + return Arrays.asList(mapper.readValue(response.getEntity().getContent(), CloudianGroup[].class)); } catch (final IOException e) { LOG.error("Failed to list Cloudian groups due to:", e); } return new ArrayList<>(); } - public boolean updateGroup(final GroupInfo group) { + public boolean updateGroup(final CloudianGroup group) { try { final HttpResponse response = post("/group", group); return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; diff --git a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianGroup.java b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianGroup.java index 4f52fe2f915..09c0cf5db22 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianGroup.java +++ b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianGroup.java @@ -20,11 +20,17 @@ package com.cloudian.client; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public class GroupInfo { +public class CloudianGroup { + String groupId; String groupName; Boolean active; + @Override + public String toString() { + return String.format("Cloudian Group [id=%s, name=%s, active=%s]", groupId, groupName, active); + } + public String getGroupId() { return groupId; } diff --git a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianUser.java b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianUser.java index 29a9666624b..64860271992 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/client/CloudianUser.java +++ b/plugins/integrations/cloudian/src/com/cloudian/client/CloudianUser.java @@ -20,7 +20,8 @@ package com.cloudian.client; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) -public class UserInfo { +public class CloudianUser { + public static final String USER = "User"; String userId; @@ -32,7 +33,7 @@ public class UserInfo { @Override public String toString() { - return String.format("User [id=%s, group id=%s, type=%s, active=%s, name=%s]", userId, groupId, userType, active, fullName); + return String.format("Cloudian User [id=%s, group id=%s, type=%s, active=%s, name=%s]", userId, groupId, userType, active, fullName); } public String getUserId() { diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java index b6401cad61e..a3dfb7d8795 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java @@ -59,6 +59,18 @@ public interface CloudianConnector extends PluggableService { ConfigKey CloudianSsoKey = new ConfigKey<>("Advanced", String.class, "cloudian.sso.key", "ss0sh5r3dk3y", "The shared single sign-on key as configured in Cloudian CMC.", true); + String getAdminUrl(); + String getCmcUrl(); + + /** + * Checks if the Cloudian Connector is disabled + * @return returns true is connector is disabled + */ boolean isConnectorDisabled(); + + /** + * Generates single-sign on URL for logged in user + * @return returns the SSO URL string + */ String generateSsoUrl(); } diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java index 286c66edaf9..2e88902fafa 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java @@ -47,8 +47,8 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.component.ComponentLifecycleBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloudian.client.CloudianClient; -import com.cloudian.client.GroupInfo; -import com.cloudian.client.UserInfo; +import com.cloudian.client.CloudianGroup; +import com.cloudian.client.CloudianUser; import com.cloudian.cloudstack.api.CloudianIsEnabledCmd; import com.cloudian.cloudstack.api.CloudianSsoLoginCmd; @@ -71,16 +71,6 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo //////////////// Plugin Methods ///////////////////// ///////////////////////////////////////////////////// - private String getAdminUrl() { - return String.format("%s://%s:%s", CloudianAdminProtocol.value(), - CloudianAdminHost.value(), CloudianAdminPort.value()); - } - - private String getCmcUrl() { - return String.format("%s://%s:%s/Cloudian/ssosecurelogin.htm?", CloudianCmcProtocol.value(), - CloudianCmcHost.value(), CloudianCmcPort.value()); - } - private CloudianClient getClient() { try { return new CloudianClient(getAdminUrl(), @@ -97,7 +87,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo return false; } final CloudianClient client = getClient(); - final GroupInfo existingGroup = client.listGroup(domain.getUuid()); + final CloudianGroup existingGroup = client.listGroup(domain.getUuid()); if (existingGroup != null) { if (!existingGroup.getActive() || !existingGroup.getGroupName().equals(domain.getPath())) { LOG.debug("Updating Cloudian group for domain uuid=" + domain.getUuid() + " name=" + domain.getName() + " path=" + domain.getPath()); @@ -109,7 +99,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo } LOG.debug("Adding Cloudian group for domain uuid=" + domain.getUuid() + " name=" + domain.getName() + " path=" + domain.getPath()); - final GroupInfo group = new GroupInfo(); + final CloudianGroup group = new CloudianGroup(); group.setGroupId(domain.getUuid()); group.setGroupName(domain.getPath()); group.setActive(true); @@ -122,7 +112,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo } final CloudianClient client = getClient(); LOG.debug("Removing Cloudian group for domain uuid=" + domain.getUuid() + " name=" + domain.getName() + " path=" + domain.getPath()); - for (final UserInfo user: client.listUsers(domain.getUuid())) { + for (final CloudianUser user: client.listUsers(domain.getUuid())) { if (client.removeUser(user.getUserId(), domain.getUuid())) { LOG.error(String.format("Failed to remove Cloudian user id=%s, while removing Cloudian group id=%s", user.getUserId(), domain.getUuid())); } @@ -137,7 +127,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo final User accountUser = userDao.listByAccount(account.getId()).get(0); final String fullName = String.format("%s %s (%s)", accountUser.getFirstname(), accountUser.getLastname(), account.getAccountName()); final CloudianClient client = getClient(); - final UserInfo existingUser = client.listUser(account.getUuid(), domain.getUuid()); + final CloudianUser existingUser = client.listUser(account.getUuid(), domain.getUuid()); if (existingUser != null) { if (!existingUser.getActive() || !existingUser.getFullName().equals(fullName)) { LOG.debug("Updating Cloudian user for account with uuid=" + account.getUuid() + " name=" + account.getAccountName()); @@ -150,12 +140,12 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo } LOG.debug("Adding Cloudian user for account with uuid=" + account.getUuid() + " name=" + account.getAccountName()); - final UserInfo user = new UserInfo(); + final CloudianUser user = new CloudianUser(); user.setUserId(account.getUuid()); user.setGroupId(domain.getUuid()); user.setFullName(fullName); user.setEmailAddr(accountUser.getEmail()); - user.setUserType(UserInfo.USER); + user.setUserType(CloudianUser.USER); user.setActive(true); return client.addUser(user); } @@ -174,6 +164,18 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo //////////////// Plugin APIs ///////////////////// ////////////////////////////////////////////////// + @Override + public String getAdminUrl() { + return String.format("%s://%s:%s", CloudianAdminProtocol.value(), + CloudianAdminHost.value(), CloudianAdminPort.value()); + } + + @Override + public String getCmcUrl() { + return String.format("%s://%s:%s/Cloudian/", CloudianCmcProtocol.value(), + CloudianCmcHost.value(), CloudianCmcPort.value()); + } + @Override public boolean isConnectorDisabled() { return !CloudianConnectorEnabled.value(); @@ -195,12 +197,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo addOrUpdateUserAccount(caller, domain); } - final String ssoParams = CloudianUtils.generateSSOUrlParams(user, group, CloudianSsoKey.value()); - if (ssoParams == null) { - return null; - } - - return getCmcUrl() + ssoParams; + return CloudianUtils.generateSSOUrl(getCmcUrl(), user, group, CloudianSsoKey.value()); } /////////////////////////////////////////////////////////// diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java index 580ea717964..bffcf8f1c5c 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java @@ -63,7 +63,7 @@ public class CloudianUtils { * @param ssoKey * @return returns SSO URL parameters or null on error */ - public static String generateSSOUrlParams(final String user, final String group, final String ssoKey) { + public static String generateSSOUrl(final String cmcUrlPath, final String user, final String group, final String ssoKey) { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("user=").append(user); stringBuilder.append("&group=").append(group); @@ -87,6 +87,6 @@ public class CloudianUtils { stringBuilder.append("explorer.htm"); } - return stringBuilder.toString(); + return cmcUrlPath + "ssosecurelogin.htm?" + stringBuilder.toString(); } } diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/api/CloudianIsEnabledCmd.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/api/CloudianIsEnabledCmd.java index 48ddceabdf1..84541a0e573 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/api/CloudianIsEnabledCmd.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/api/CloudianIsEnabledCmd.java @@ -22,13 +22,13 @@ import javax.inject.Inject; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.response.SuccessResponse; import com.cloud.user.Account; import com.cloudian.cloudstack.CloudianConnector; +import com.cloudian.cloudstack.response.CloudianEnabledResponse; @APICommand(name = CloudianIsEnabledCmd.APINAME, description = "Checks if the Cloudian Connector is enabled", - responseObject = SuccessResponse.class, + responseObject = CloudianEnabledResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.11.0", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) @@ -55,9 +55,10 @@ public class CloudianIsEnabledCmd extends BaseCmd { @Override public void execute() { - final boolean isEnabled = !connector.isConnectorDisabled(); - final SuccessResponse response = new SuccessResponse(); - response.setSuccess(isEnabled); + final CloudianEnabledResponse response = new CloudianEnabledResponse(); + response.setEnabled(!connector.isConnectorDisabled()); + response.setCmcUrl(connector.getCmcUrl()); + response.setObjectName(APINAME.toLowerCase()); response.setResponseName(getCommandName()); setResponseObject(response); } diff --git a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/response/CloudianEnabledResponse.java b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/response/CloudianEnabledResponse.java index 6c630039f38..c4fb8fdb587 100644 --- a/plugins/integrations/cloudian/src/com/cloudian/cloudstack/response/CloudianEnabledResponse.java +++ b/plugins/integrations/cloudian/src/com/cloudian/cloudstack/response/CloudianEnabledResponse.java @@ -17,5 +17,34 @@ package com.cloudian.cloudstack.response; -public class CloudianEnabledResponse { +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class CloudianEnabledResponse extends BaseResponse { + @SerializedName(ApiConstants.ENABLED) + @Param(description = "the Cloudian connector enabled state") + private Boolean enabled; + + @SerializedName(ApiConstants.URL) + @Param(description = "the Cloudian Management Console base URL") + private String cmcUrl; + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getCmcUrl() { + return cmcUrl; + } + + public void setCmcUrl(String cmcUrl) { + this.cmcUrl = cmcUrl; + } } diff --git a/plugins/integrations/cloudian/test/com/cloudian/cloudstack/CloudianClientTest.java b/plugins/integrations/cloudian/test/com/cloudian/cloudstack/CloudianClientTest.java index ce7893874a3..57d2b12719e 100644 --- a/plugins/integrations/cloudian/test/com/cloudian/cloudstack/CloudianClientTest.java +++ b/plugins/integrations/cloudian/test/com/cloudian/cloudstack/CloudianClientTest.java @@ -7,8 +7,8 @@ import org.junit.Before; import org.junit.Test; import com.cloudian.client.CloudianClient; -import com.cloudian.client.GroupInfo; -import com.cloudian.client.UserInfo; +import com.cloudian.client.CloudianGroup; +import com.cloudian.client.CloudianUser; public class CloudianClientTest { @@ -29,7 +29,7 @@ public class CloudianClientTest { @Test public void listUserAccount() throws Exception { - List users = client.listUsers("0"); + List users = client.listUsers("0"); } @Test @@ -38,7 +38,7 @@ public class CloudianClientTest { @Test public void removeUserAccount() throws Exception { - for (UserInfo user : client.listUsers("2ddabedc-4733-4cdf-80b1-abbd9d027005")) { + for (CloudianUser user : client.listUsers("2ddabedc-4733-4cdf-80b1-abbd9d027005")) { boolean result = client.removeUser(user.getUserId(), user.getGroupId()); } } @@ -49,7 +49,7 @@ public class CloudianClientTest { @Test public void listGroup() throws Exception { - List groups = client.listGroups(); + List groups = client.listGroups(); } @Test