mirror of https://github.com/apache/cloudstack.git
cloudian: wip sso integration
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
170ad669e6
commit
db7697216b
|
|
@ -19,9 +19,12 @@ package com.cloudian.cloudstack;
|
|||
|
||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||
|
||||
import com.cloud.domain.Domain;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
|
||||
public interface CloudianConnector extends PluggableService {
|
||||
|
||||
ConfigKey<Boolean> CloudianConnectorEnabled = new ConfigKey<>("Advanced", Boolean.class, "cloudian.connector.enabled", "false",
|
||||
"If set to true, this enables the Cloudian Connector for CloudStack.", true);
|
||||
|
||||
|
|
@ -55,4 +58,10 @@ public interface CloudianConnector extends PluggableService {
|
|||
ConfigKey<String> CloudianSsoKey = new ConfigKey<>("Advanced", String.class, "cloudian.sso.key", "ss0sh5r3dk3y",
|
||||
"The shared single sign-on key as configured in Cloudian CMC.", true);
|
||||
|
||||
boolean isConnectorDisabled();
|
||||
String generateSsoUrl();
|
||||
boolean addGroup(final Domain domain);
|
||||
boolean removeGroup(final Domain domain);
|
||||
boolean addUserAccount(final Account account);
|
||||
boolean removeUserAccount(final Account account);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@ import com.cloud.user.AccountManager;
|
|||
import com.cloud.user.DomainManager;
|
||||
import com.cloud.user.dao.AccountDao;
|
||||
import com.cloud.utils.component.ComponentLifecycleBase;
|
||||
import com.cloudian.cloudstack.api.CloudianIsEnabledCmd;
|
||||
import com.cloudian.cloudstack.api.CloudianSsoLoginCmd;
|
||||
|
||||
public class CloudianConnectorImpl extends ComponentLifecycleBase implements CloudianConnector, Configurable {
|
||||
public static final Logger LOG = Logger.getLogger(CloudianConnectorImpl.class);
|
||||
private static final Logger LOG = Logger.getLogger(CloudianConnectorImpl.class);
|
||||
|
||||
@Inject
|
||||
private AccountDao accountDao;
|
||||
|
|
@ -51,6 +53,59 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo
|
|||
@Inject
|
||||
private MessageBus messageBus;
|
||||
|
||||
@Override
|
||||
public boolean isConnectorDisabled() {
|
||||
return !CloudianConnectorEnabled.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSsoUrl() {
|
||||
// add user/group in CMC if not available
|
||||
// return generated login url using sso shared key
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addGroup(final Domain domain) {
|
||||
if (domain == null || isConnectorDisabled()) {
|
||||
return false;
|
||||
}
|
||||
LOG.debug("Adding Cloudian group against domain uuid=" + domain.getUuid() + " name=" + domain.getName() + " path=" + domain.getPath());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeGroup(final Domain domain) {
|
||||
if (domain == null || isConnectorDisabled()) {
|
||||
return false;
|
||||
}
|
||||
LOG.debug("Removing Cloudian group against domain uuid=" + domain.getUuid() + " name=" + domain.getName() + " path=" + domain.getPath());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addUserAccount(final Account account) {
|
||||
if (account == null || isConnectorDisabled()) {
|
||||
return false;
|
||||
}
|
||||
LOG.debug("Adding Cloudian user account with uuid=" + account.getUuid() + " name=" + account.getAccountName());
|
||||
final Domain domain = domainDao.findById(account.getId());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeUserAccount(final Account account) {
|
||||
if (account == null || isConnectorDisabled()) {
|
||||
return false;
|
||||
}
|
||||
LOG.debug("Removing Cloudian user account with uuid=" + account.getUuid() + " name=" + account.getAccountName());
|
||||
final Domain domain = domainDao.findById(account.getId());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
|
|
@ -59,41 +114,34 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo
|
|||
messageBus.subscribe(AccountManager.MESSAGE_ADD_ACCOUNT_EVENT, new MessageSubscriber() {
|
||||
@Override
|
||||
public void onPublishMessage(String senderAddress, String subject, Object args) {
|
||||
Map<Long, Long> accountGroupMap = (Map<Long, Long>) args;
|
||||
Long accountId = accountGroupMap.keySet().iterator().next();
|
||||
// TODO: check and create user in CMC
|
||||
final Map<Long, Long> accountGroupMap = (Map<Long, Long>) args;
|
||||
final Long accountId = accountGroupMap.keySet().iterator().next();
|
||||
final Account account = accountDao.findById(accountId);
|
||||
LOG.info("Creating account id=" + accountId + " with uuid=" + account.getUuid());
|
||||
addUserAccount(account);
|
||||
}
|
||||
});
|
||||
|
||||
messageBus.subscribe(AccountManager.MESSAGE_REMOVE_ACCOUNT_EVENT, new MessageSubscriber() {
|
||||
@Override
|
||||
public void onPublishMessage(String senderAddress, String subject, Object args) {
|
||||
Long accountId = (Long) args;
|
||||
// TODO: remove/disable user in CMC
|
||||
final Account account = accountDao.findByIdIncludingRemoved(accountId);
|
||||
LOG.info("Removing account id=" + accountId + " with uuid=" + account.getUuid());
|
||||
|
||||
final Account account = accountDao.findByIdIncludingRemoved((Long) args);
|
||||
removeUserAccount(account);
|
||||
}
|
||||
});
|
||||
|
||||
messageBus.subscribe(DomainManager.MESSAGE_ADD_DOMAIN_EVENT, new MessageSubscriber() {
|
||||
@Override
|
||||
public void onPublishMessage(String senderAddress, String subject, Object args) {
|
||||
Long domainId = (Long) args;
|
||||
Domain domain = domainDao.findById(domainId);
|
||||
// TODO: check and create group in CMC
|
||||
LOG.info("Adding domain id=" + domainId + " with uuid=" + domain.getUuid());
|
||||
final Domain domain = domainDao.findById((Long) args);
|
||||
addGroup(domain);
|
||||
}
|
||||
});
|
||||
|
||||
messageBus.subscribe(DomainManager.MESSAGE_REMOVE_DOMAIN_EVENT, new MessageSubscriber() {
|
||||
@Override
|
||||
public void onPublishMessage(String senderAddress, String subject, Object args) {
|
||||
DomainVO domain = (DomainVO) args;
|
||||
// TODO: remove/disable group in CMC
|
||||
LOG.info("Removing domain id=" + domain.getId() + " with uuid=" + domain.getUuid());
|
||||
final DomainVO domain = (DomainVO) args;
|
||||
removeGroup(domain);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -102,10 +150,12 @@ public class CloudianConnectorImpl extends ComponentLifecycleBase implements Clo
|
|||
|
||||
@Override
|
||||
public List<Class<?>> getCommands() {
|
||||
List<Class<?>> cmdList = new ArrayList<Class<?>>();
|
||||
if (!CloudianConnectorEnabled.value()) {
|
||||
final List<Class<?>> cmdList = new ArrayList<Class<?>>();
|
||||
cmdList.add(CloudianIsEnabledCmd.class);
|
||||
if (isConnectorDisabled()) {
|
||||
return cmdList;
|
||||
}
|
||||
cmdList.add(CloudianSsoLoginCmd.class);
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// 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.api;
|
||||
|
||||
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;
|
||||
|
||||
@APICommand(name = CloudianIsEnabledCmd.APINAME, description = "Checks if the Cloudian Connector is enabled",
|
||||
responseObject = SuccessResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||
since = "4.11.0",
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||
public class CloudianIsEnabledCmd extends BaseCmd {
|
||||
public static final String APINAME = "cloudianIsEnabled";
|
||||
|
||||
@Inject
|
||||
private CloudianConnector connector;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
final boolean isEnabled = !connector.isConnectorDisabled();
|
||||
final SuccessResponse response = new SuccessResponse();
|
||||
response.setSuccess(isEnabled);
|
||||
response.setDisplayText(isEnabled ? "Cloudian Connector is enabled" : "Cloudian Connector is disabled");
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// 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.api;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloudian.cloudstack.CloudianConnector;
|
||||
import com.cloudian.cloudstack.response.CloudianSsoLoginResponse;
|
||||
|
||||
@APICommand(name = CloudianSsoLoginCmd.APINAME, description = "Generates single-sign-on login url for logged-in CloudStack user to access the Cloudian Management Console",
|
||||
responseObject = CloudianSsoLoginResponse.class,
|
||||
since = "4.11.0",
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
|
||||
public class CloudianSsoLoginCmd extends BaseCmd {
|
||||
public static final String APINAME = "cloudianSsoLogin";
|
||||
|
||||
@Inject
|
||||
private CloudianConnector connector;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return Account.ACCOUNT_ID_SYSTEM;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
final CloudianSsoLoginResponse response = new CloudianSsoLoginResponse();
|
||||
response.setSsoRedirectUrl(connector.generateSsoUrl());
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,24 @@
|
|||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package com.cloudian.cloudstack.api;
|
||||
package com.cloudian.cloudstack.response;
|
||||
|
||||
public class CloudianSsoCmd {
|
||||
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 CloudianSsoLoginResponse extends BaseResponse {
|
||||
@SerializedName(ApiConstants.URL)
|
||||
@Param(description = "the sso redirect url")
|
||||
private String ssoRedirectUrl;
|
||||
|
||||
public String getSsoRedirectUrl() {
|
||||
return ssoRedirectUrl;
|
||||
}
|
||||
|
||||
public void setSsoRedirectUrl(final String ssoRedirectUrl) {
|
||||
this.ssoRedirectUrl = ssoRedirectUrl;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,11 +22,35 @@
|
|||
title: 'Cloudian Storage',
|
||||
showOnNavigation: true,
|
||||
preFilter: function(args) {
|
||||
// FIXME: show/hide plugin based on if plugin/connector is enabled?
|
||||
return true;
|
||||
var pluginEnabled = false;
|
||||
$.ajax({
|
||||
url: createURL('cloudianIsEnabled'),
|
||||
async: false,
|
||||
success: function(json) {
|
||||
pluginEnabled = json.cloudianisenabledresponse.success;
|
||||
},
|
||||
error: function(data) {
|
||||
pluginEnabled = false;
|
||||
}
|
||||
});
|
||||
return pluginEnabled;
|
||||
},
|
||||
show: function() {
|
||||
return $('<div>').html('Cloudian Storage section');
|
||||
var ssoUrl = '';
|
||||
var description = 'Cloudian Storage should open in another window.';
|
||||
$.ajax({
|
||||
url: createURL('cloudianSsoLogin'),
|
||||
async: false,
|
||||
success: function(json) {
|
||||
ssoUrl = json.cloudianssologinresponse.url;
|
||||
// open new tab using http POST
|
||||
},
|
||||
error: function(data) {
|
||||
description = 'Single-Sign-On failed for Cloudian Storage.';
|
||||
}
|
||||
});
|
||||
return $('<div>').html(description);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue