diff --git a/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java index 02d8b4a21b2..730ad6ea7f4 100644 --- a/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java +++ b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnector.java @@ -40,12 +40,15 @@ public interface CloudianConnector extends PluggableService { ConfigKey CloudianValidateSSLSecurity = new ConfigKey<>("Advanced", String.class, "cloudian.validate.ssl", "false", "When set to true, this will validate the SSL certificate when connecting to https/ssl enabled admin host.", true); - ConfigKey CloudianAdminUser = new ConfigKey<>("Advanced", String.class, "cloudian.admin.user", "admin", + ConfigKey CloudianAdminUser = new ConfigKey<>("Advanced", String.class, "cloudian.admin.user", "sysadmin", "The system admin user for accessing the Cloudian Admin server.", true); ConfigKey CloudianAdminPassword = new ConfigKey<>("Advanced", String.class, "cloudian.admin.password", "public", "The system admin password for the Cloudian Admin server.", true); + ConfigKey CloudianCmcAdminUser = new ConfigKey<>("Advanced", String.class, "cloudian.cmc.admin.user", "admin", + "The admin user name for accessing the Cloudian Management Console.", true); + ConfigKey CloudianCmcHost = new ConfigKey<>("Advanced", String.class, "cloudian.cmc.host", "cmc.cloudian.com", "The hostname of the Cloudian Management Console.", true); diff --git a/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java index 6ad289c21f6..35ecc4bf207 100644 --- a/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java +++ b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianConnectorImpl.java @@ -17,24 +17,19 @@ package com.cloudian.cloudstack; -import static com.amazonaws.services.s3.internal.Constants.HMAC_SHA1_ALGORITHM; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageSubscriber; -import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import com.cloud.domain.Domain; @@ -47,7 +42,6 @@ import com.cloud.user.dao.AccountDao; import com.cloud.utils.component.ComponentLifecycleBase; import com.cloudian.cloudstack.api.CloudianIsEnabledCmd; import com.cloudian.cloudstack.api.CloudianSsoLoginCmd; -import com.google.common.base.Strings; public class CloudianConnectorImpl extends ComponentLifecycleBase implements CloudianConnector, Configurable { private static final Logger LOG = Logger.getLogger(CloudianConnectorImpl.class); @@ -66,74 +60,28 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo return !CloudianConnectorEnabled.value(); } - /** - * Computes RFC 2104-compliant HMAC signature. - * - * @param data The data to be signed. - * @param key The signing key. - * @return The Base64-encoded RFC 2104-compliant HMAC signature. - */ - public static String calculateRFC2104HMAC(String data, String key) { - try { - // get an hmac_sha1 key from the raw key bytes - SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM); - - // get an hmac_sha1 Mac instance and initialize with the signing key - Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); - mac.init(signingKey); - - // compute the hmac on input data bytes - byte[] rawHmac = mac.doFinal(data.getBytes()); - - // return the base64-encode the hmac - return Base64.encodeBase64String(rawHmac); - } catch (Exception e) { - // LOG? - } - return null; - } - - public static String genSSOParams(String userId, String groupId, String key) { - StringBuilder sts = new StringBuilder(); - sts.append("user="); - sts.append(userId); - sts.append("&group="); - sts.append(groupId); - sts.append("×tamp="); - sts.append(System.currentTimeMillis()); - - String signature = calculateRFC2104HMAC(sts.toString(), key); - if (Strings.isNullOrEmpty(signature)) { - return null; - } - sts.append("&signature="); - try { - sts.append(URLEncoder.encode(signature, "UTF-8")); - } catch (UnsupportedEncodingException e) { - return null; - } - - sts.append("&redirect="); - if (groupId.equals("0")) { - sts.append("admin.htm"); - } else { - sts.append("explorer.htm"); - } - - return sts.toString(); - } - @Override public String generateSsoUrl() { - // add user/group in CMC if not available - // return generated login url using sso shared key + // check and add user/group in CMC if not available - String ssoparams = genSSOParams("admin", "0", CloudianSsoKey.value()); - if (ssoparams == null) { + final Account caller = CallContext.current().getCallingAccount(); + final Domain domain = domainDao.findById(caller.getDomainId()); + + String user = caller.getUuid(); + String group = domain.getUuid(); + + if (caller.getAccountName().equals("admin") && caller.getRoleId() == RoleType.Admin.getId()) { + user = CloudianCmcAdminUser.value(); + group = "0"; + } + + final String ssoParams = CloudianUtils.generateSSOUrlParams(user, group, CloudianSsoKey.value()); + if (ssoParams == null) { return null; } - return "https://cmc.hs.yadav.xyz:8443/Cloudian/ssosecurelogin.htm?" + ssoparams; + return String.format("%s://%s:%s/Cloudian/ssosecurelogin.htm?%s", CloudianCmcProtocol.value(), + CloudianCmcHost.value(), CloudianCmcPort.value(), ssoParams); } @Override @@ -245,6 +193,7 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo CloudianAdminPassword, CloudianAdminProtocol, CloudianValidateSSLSecurity, + CloudianCmcAdminUser, CloudianCmcHost, CloudianCmcPort, CloudianCmcProtocol, diff --git a/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java new file mode 100644 index 00000000000..580ea717964 --- /dev/null +++ b/plugins/connectors/cloudian/src/com/cloudian/cloudstack/CloudianUtils.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloudian.cloudstack; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import com.cloud.utils.HttpUtils; +import com.google.common.base.Strings; + +public class CloudianUtils { + + private static final Logger LOG = Logger.getLogger(CloudianUtils.class); + private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; + + /** + * Generates RFC-2104 compliant HMAC signature + * @param data + * @param key + * @return returns the generated signature or null on error + */ + public static String generateHMACSignature(final String data, final String key) { + if (Strings. isNullOrEmpty(data) || Strings.isNullOrEmpty(key)) { + return null; + } + try { + SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM); + Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); + mac.init(signingKey); + byte[] rawHmac = mac.doFinal(data.getBytes()); + return Base64.encodeBase64String(rawHmac); + } catch (final Exception e) { + LOG.error("Failed to generate HMAC signature from provided data and key, due to: ", e); + } + return null; + } + + /** + * Generates URL parameters for single-sign on URL + * @param user + * @param group + * @param ssoKey + * @return returns SSO URL parameters or null on error + */ + public static String generateSSOUrlParams(final String user, final String group, final String ssoKey) { + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("user=").append(user); + stringBuilder.append("&group=").append(group); + stringBuilder.append("×tamp=").append(System.currentTimeMillis()); + + final String signature = generateHMACSignature(stringBuilder.toString(), ssoKey); + if (Strings.isNullOrEmpty(signature)) { + return null; + } + + try { + stringBuilder.append("&signature=").append(URLEncoder.encode(signature, HttpUtils.UTF_8)); + } catch (final UnsupportedEncodingException e) { + return null; + } + + stringBuilder.append("&redirect="); + if (group.equals("0")) { + stringBuilder.append("admin.htm"); + } else { + stringBuilder.append("explorer.htm"); + } + + return stringBuilder.toString(); + } +}