diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 4ba3b9cdab6..0e83aeb4390 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -221,3 +221,7 @@ listHypervisors=com.cloud.api.commands.ListHypervisorsCmd;15 createRemoteAccessVpn=com.cloud.api.commands.CreateRemoteAccessVpnCmd;15 deleteRemoteAccessVpn=com.cloud.api.commands.DeleteRemoteAccessVpnCmd;15 listRemoteAccessVpns=com.cloud.api.commands.ListRemoteAccessVpnsCmd;15 + +addVpnUser=com.cloud.api.commands.AddVpnUserCmd;15 +removeVpnUser=com.cloud.api.commands.RemoveVpnUserCmd;15 +listVpnUsers=com.cloud.api.commands.ListVpnUsersCmd;15 diff --git a/core/src/com/cloud/event/EventTypes.java b/core/src/com/cloud/event/EventTypes.java index 24de0d57749..eb7d601cfdd 100755 --- a/core/src/com/cloud/event/EventTypes.java +++ b/core/src/com/cloud/event/EventTypes.java @@ -166,5 +166,7 @@ public class EventTypes { //VPN public static final String EVENT_REMOTE_ACCESS_VPN_CREATE = "VPN.REMOTE.ACCESS.CREATE"; public static final String EVENT_REMOTE_ACCESS_VPN_DESTROY = "VPN.REMOTE.ACCESS.DESTROY"; - public static final String EVENT_VPN_USERS_ADD_OR_DELETE = "VPN.USERS.ADD.OR.DELETE"; + public static final String EVENT_VPN_USER_ADD = "VPN.USER.ADD"; + public static final String EVENT_VPN_USER_REMOVE = "VPN.USER.REMOVE"; + } diff --git a/server/src/com/cloud/api/commands/VpnUserConfigCmd.java b/server/src/com/cloud/api/commands/AddVpnUserCmd.java similarity index 58% rename from server/src/com/cloud/api/commands/VpnUserConfigCmd.java rename to server/src/com/cloud/api/commands/AddVpnUserCmd.java index debea8cbae4..bcb13e6f675 100644 --- a/server/src/com/cloud/api/commands/VpnUserConfigCmd.java +++ b/server/src/com/cloud/api/commands/AddVpnUserCmd.java @@ -25,42 +25,38 @@ import com.cloud.api.BaseAsyncCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.response.RemoteAccessVpnResponse; +import com.cloud.api.response.SuccessResponse; import com.cloud.event.EventTypes; import com.cloud.network.NetworkManager; import com.cloud.network.RemoteAccessVpnVO; import com.cloud.user.Account; import com.cloud.user.UserContext; -@Implementation( method="addRemoveVpnUsers", manager=NetworkManager.class, description="Adds or removes vpn users") -public class VpnUserConfigCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(VpnUserConfigCmd.class.getName()); +@Implementation( method="addVpnUser", manager=NetworkManager.class, description="Adds vpn users") +public class AddVpnUserCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(AddVpnUserCmd.class.getName()); - private static final String s_name = "addremovevpnusersresponse"; + private static final String s_name = "addvpnuserresponse"; ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// - @Parameter(name="zoneid", type=CommandType.LONG, required=true, description="zone id where the vpn server needs to be created") - private Long zoneId; + @Parameter(name="username", type=CommandType.STRING, required=true, description="username for the vpn user") + private String userName; - @Parameter(name="publicip", type=CommandType.STRING, required=false, description="public ip address of the vpn server") - private String publicIp; - - @Parameter(name="iprange", type=CommandType.STRING, required=false, description="the range of ip addresses to allocate to vpn clients. The first ip in the range will be taken by the vpn server") - private String ipRange; + @Parameter(name="password", type=CommandType.STRING, required=false, description="password for the username") + private String password; - @Parameter(name="account", type=CommandType.STRING, description="an optional account for the virtual machine. Must be used with domainId.") + @Parameter(name="account", type=CommandType.STRING, description="an optional account for the vpn user. Must be used with domainId.") private String accountName; - @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.") private Long domainId; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// - public String getPublicIp() { - return publicIp; - } + public String getAccountName() { return accountName; @@ -70,25 +66,22 @@ public class VpnUserConfigCmd extends BaseAsyncCmd { return domainId; } - public void setPublicIp(String publicIp) { - this.publicIp = publicIp; + public String getUserName() { + return userName; } - public String getIpRange() { - return ipRange; + public void setUserName(String userName) { + this.userName = userName; } - public void setIpRange(String ipRange) { - this.ipRange = ipRange; + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; } - public void setZoneId(Long zoneId) { - this.zoneId = zoneId; - } - - public Long getZoneId() { - return zoneId; - } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -100,16 +93,10 @@ public class VpnUserConfigCmd extends BaseAsyncCmd { } @Override @SuppressWarnings("unchecked") - public RemoteAccessVpnResponse getResponse() { - RemoteAccessVpnVO responseObj = (RemoteAccessVpnVO)getResponseObject(); - - RemoteAccessVpnResponse response = new RemoteAccessVpnResponse(); - response.setId(responseObj.getId()); - response.setPublicIp(responseObj.getVpnServerAddress()); - response.setIpRange(responseObj.getIpRange()); - response.setAccountName(responseObj.getAccountName()); - response.setDomainId(responseObj.getDomainId()); - response.setDomainName(ApiDBUtils.findDomainById(responseObj.getDomainId()).getName()); + public SuccessResponse getResponse() { + Boolean success = (Boolean)getResponseObject(); + SuccessResponse response = new SuccessResponse(); + response.setSuccess(success); response.setResponseName(getName()); return response; } @@ -135,12 +122,14 @@ public class VpnUserConfigCmd extends BaseAsyncCmd { @Override public String getEventDescription() { - return "Create Remote Access VPN for account " + getAccountId() + " in zone " + getZoneId(); + return "Add Remote Access VPN user for account " + getAccountId() + " username= " + getUserName(); } + + @Override public String getEventType() { - return EventTypes.EVENT_REMOTE_ACCESS_VPN_CREATE; + return EventTypes.EVENT_VPN_USER_ADD; } diff --git a/server/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java b/server/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java index 4f0f86a69ea..1ab9f342416 100644 --- a/server/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java +++ b/server/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java @@ -49,10 +49,10 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Parameter(name="iprange", type=CommandType.STRING, required=false, description="the range of ip addresses to allocate to vpn clients. The first ip in the range will be taken by the vpn server") private String ipRange; - @Parameter(name="account", type=CommandType.STRING, description="an optional account for the virtual machine. Must be used with domainId.") + @Parameter(name="account", type=CommandType.STRING, description="an optional account for the VPN. Must be used with domainId.") private String accountName; - @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the VPN. If the account parameter is used, domainId must also be used.") private Long domainId; ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/api/commands/RemoveVpnUserCmd.java b/server/src/com/cloud/api/commands/RemoveVpnUserCmd.java new file mode 100644 index 00000000000..395bbfce003 --- /dev/null +++ b/server/src/com/cloud/api/commands/RemoveVpnUserCmd.java @@ -0,0 +1,126 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.api.commands; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiDBUtils; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.response.RemoteAccessVpnResponse; +import com.cloud.api.response.SuccessResponse; +import com.cloud.event.EventTypes; +import com.cloud.network.NetworkManager; +import com.cloud.network.RemoteAccessVpnVO; +import com.cloud.user.Account; +import com.cloud.user.UserContext; + +@Implementation( method="removeVpnUser", manager=NetworkManager.class, description="Removes vpn user") +public class RemoveVpnUserCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(RemoveVpnUserCmd.class.getName()); + + private static final String s_name = "removevpnuserresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name="username", type=CommandType.STRING, required=true, description="username for the vpn user") + private String userName; + + @Parameter(name="account", type=CommandType.STRING, description="an optional account for the vpn user. Must be used with domainId.") + private String accountName; + + @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the vpn user. If the account parameter is used, domainId must also be used.") + private Long domainId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + + + public String getName() { + return s_name; + } + + @Override @SuppressWarnings("unchecked") + public SuccessResponse getResponse() { + Boolean success = (Boolean)getResponseObject(); + SuccessResponse response = new SuccessResponse(); + response.setSuccess(success); + response.setResponseName(getName()); + return response; + } + + @Override + public long getAccountId() { + Account account = (Account)UserContext.current().getAccount(); + if ((account == null) || isAdmin(account.getType())) { + if ((domainId != null) && (accountName != null)) { + Account userAccount = ApiDBUtils.findAccountByNameDomain(accountName, domainId); + if (userAccount != null) { + return userAccount.getId(); + } + } + } + + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + @Override + public String getEventDescription() { + return "Remove Remote Access VPN user for account " + getAccountId() + " username= " + getUserName(); + } + + + @Override + public String getEventType() { + return EventTypes.EVENT_VPN_USER_REMOVE; + } + + + +} diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 2d0fccd6ed7..958f239bd8a 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -33,11 +33,12 @@ import com.cloud.api.commands.DisassociateIPAddrCmd; import com.cloud.api.commands.ListPortForwardingRulesCmd; import com.cloud.api.commands.RebootRouterCmd; import com.cloud.api.commands.RemoveFromLoadBalancerRuleCmd; +import com.cloud.api.commands.RemoveVpnUserCmd; import com.cloud.api.commands.StartRouterCmd; import com.cloud.api.commands.StopRouterCmd; import com.cloud.api.commands.UpdateLoadBalancerRuleCmd; import com.cloud.api.commands.UpgradeRouterCmd; -import com.cloud.api.commands.VpnUserConfigCmd; +import com.cloud.api.commands.AddVpnUserCmd; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; @@ -343,5 +344,7 @@ public interface NetworkManager extends Manager { */ public boolean destroyRemoteAccessVpn(DeleteRemoteAccessVpnCmd cmd) throws ConcurrentOperationException; - boolean addRemoveVpnUsers(VpnUserConfigCmd cmd) throws ConcurrentOperationException; + boolean addVpnUser(AddVpnUserCmd cmd) throws ConcurrentOperationException; + + boolean removeVpnUser(RemoveVpnUserCmd cmd) throws ConcurrentOperationException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index e07d89d0777..48b42b5f766 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -43,6 +43,7 @@ import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.api.BaseCmd; import com.cloud.api.ServerApiException; +import com.cloud.api.commands.AddVpnUserCmd; import com.cloud.api.commands.AssignToLoadBalancerRuleCmd; import com.cloud.api.commands.AssociateIPAddrCmd; import com.cloud.api.commands.CreateIPForwardingRuleCmd; @@ -55,6 +56,7 @@ import com.cloud.api.commands.DisassociateIPAddrCmd; import com.cloud.api.commands.ListPortForwardingRulesCmd; import com.cloud.api.commands.RebootRouterCmd; import com.cloud.api.commands.RemoveFromLoadBalancerRuleCmd; +import com.cloud.api.commands.RemoveVpnUserCmd; import com.cloud.api.commands.StartRouterCmd; import com.cloud.api.commands.StopRouterCmd; import com.cloud.api.commands.UpdateLoadBalancerRuleCmd; @@ -2744,79 +2746,82 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { } @Override + public boolean addVpnUser(AddVpnUserCmd cmd) throws ConcurrentOperationException { + Long userId = UserContext.current().getUserId(); + Account account = getAccountForApiCommand(cmd.getAccountName(), cmd.getDomainId()); + EventUtils.saveStartedEvent(userId, account.getId(), EventTypes.EVENT_VPN_USER_ADD, "Add VPN user for account: " + account.getAccountName(), cmd.getStartEventId()); + + boolean added = addRemoveVpnUser(account, cmd.getUserName(), cmd.getPassword(), true); + if (added) { + EventUtils.saveEvent(userId, account.getId(), EventTypes.EVENT_VPN_USER_ADD, "Added a VPN user for account: " + account.getAccountName() + " username= " + cmd.getUserName()); + } else { + EventUtils.saveEvent(userId, account.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VPN_USER_ADD, "Unable to add VPN user for account: ", account.getAccountName() + " username= " + cmd.getUserName()); + } + return added; + + } + + @Override + public boolean removeVpnUser(RemoveVpnUserCmd cmd) throws ConcurrentOperationException { + Long userId = UserContext.current().getUserId(); + Account account = getAccountForApiCommand(cmd.getAccountName(), cmd.getDomainId()); + EventUtils.saveStartedEvent(userId, account.getId(), EventTypes.EVENT_VPN_USER_REMOVE, "Remove VPN user for account: " + account.getAccountName(), cmd.getStartEventId()); + + boolean added = addRemoveVpnUser(account, cmd.getUserName(), null, false); + if (added) { + EventUtils.saveEvent(userId, account.getId(), EventTypes.EVENT_VPN_USER_REMOVE, "Removed a VPN user for account: " + account.getAccountName() + " username= " + cmd.getUserName()); + } else { + EventUtils.saveEvent(userId, account.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VPN_USER_ADD, "Unable to remove VPN user for account: ", account.getAccountName() + " username= " + cmd.getUserName()); + } + return added; + + } + @DB - public boolean addRemoveVpnUsers(VpnUserConfigCmd cmd) throws ConcurrentOperationException { - Long userId = UserContext.current().getUserId(); - Account account = getAccountForApiCommand(cmd.getAccountName(), cmd.getDomainId()); - EventUtils.saveStartedEvent(userId, account.getId(), EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Add/remove VPN users for account: " + account.getAccountName(), cmd.getStartEventId()); + protected boolean addRemoveVpnUser(Account account, String username, String password, boolean add) throws ConcurrentOperationException { List vpnVOList = _remoteAccessVpnDao.findByAccount(account.getId()); - String publicIp = vpnVO.getVpnServerAddress(); - Long vpnId = vpnVO.getId(); + Transaction txn = Transaction.currentTxn(); txn.start(); boolean locked = false; - boolean created = false; + boolean success = true; + VpnUserVO user = null; + final String op = add ? "add" : "remove"; try { - IPAddressVO ipAddr = _ipAddressDao.acquire(publicIp); - if (ipAddr == null) { - throw new ConcurrentOperationException("Another operation active, unable to create vpn"); + account = _accountDao.acquireInLockTable(account.getId()); + if (account == null) { + throw new ConcurrentOperationException("Unable to " + op + " vpn user: Another operation active"); } locked = true; + List addVpnUsers = new ArrayList(); + List removeVpnUsers = new ArrayList(); + if (add) { + user = _vpnUsersDao.persist(new VpnUserVO(account.getId(), username, password)); + addVpnUsers.add(user); - vpnVO = _routerMgr.startRemoteAccessVpn(vpnVO); - created = (vpnVO != null); - - return vpnVO; + } else { + user = _vpnUsersDao.findByAccountAndUsername(account.getId(), username); + if (user == null) { + throw new InvalidParameterValueException("Could not find vpn user " + username); + } + removeVpnUsers.add(user); + } + for (RemoteAccessVpnVO vpn : vpnVOList) { + success = success && _routerMgr.addRemoveVpnUsers(vpn, addVpnUsers, removeVpnUsers); + } + return success; } finally { - if (created) { - EventUtils.saveEvent(userId, account.getId(), EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Created a Remote Access VPN for account: " + account.getAccountName() + " in zone " + cmd.getZoneId()); - } else { - EventUtils.saveEvent(userId, account.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Unable to create Remote Access VPN ", account.getAccountName() + " in zone " + cmd.getZoneId()); - _remoteAccessVpnDao.remove(vpnId); - } - txn.commit(); + if (success) { + txn.rollback(); + } else { + txn.commit(); + } if (locked) { - _ipAddressDao.release(publicIp); + _accountDao.releaseFromLockTable(account.getId()); } } } - @Override - @DB - public boolean addRemoveVpnUsers(VpnUserConfigCmd cmd) throws ConcurrentOperationException { - Long userId = UserContext.current().getUserId(); - Account account = getAccountForApiCommand(cmd.getAccountName(), cmd.getDomainId()); - EventUtils.saveStartedEvent(userId, account.getId(), EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Add/remove VPN users for account: " + account.getAccountName(), cmd.getStartEventId()); - List vpnVOList = _remoteAccessVpnDao.findByAccount(account.getId()); - String publicIp = vpnVO.getVpnServerAddress(); - Long vpnId = vpnVO.getId(); - Transaction txn = Transaction.currentTxn(); - txn.start(); - boolean locked = false; - boolean created = false; - try { - IPAddressVO ipAddr = _ipAddressDao.acquire(publicIp); - if (ipAddr == null) { - throw new ConcurrentOperationException("Another operation active, unable to create vpn"); - } - locked = true; - - vpnVO = _routerMgr.startRemoteAccessVpn(vpnVO); - created = (vpnVO != null); - - return vpnVO; - } finally { - if (created) { - EventUtils.saveEvent(userId, account.getId(), EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Created a Remote Access VPN for account: " + account.getAccountName() + " in zone " + cmd.getZoneId()); - } else { - EventUtils.saveEvent(userId, account.getId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VPN_USERS_ADD_OR_DELETE, "Unable to create Remote Access VPN ", account.getAccountName() + " in zone " + cmd.getZoneId()); - _remoteAccessVpnDao.remove(vpnId); - } - txn.commit(); - if (locked) { - _ipAddressDao.release(publicIp); - } - } - } + } diff --git a/server/src/com/cloud/network/router/DomainRouterManager.java b/server/src/com/cloud/network/router/DomainRouterManager.java index c9436119bcf..31886d53a15 100644 --- a/server/src/com/cloud/network/router/DomainRouterManager.java +++ b/server/src/com/cloud/network/router/DomainRouterManager.java @@ -177,8 +177,7 @@ public interface DomainRouterManager extends Manager { RemoteAccessVpnVO startRemoteAccessVpn(RemoteAccessVpnVO vpnVO); - boolean addRemoveVpnUsers(RemoteAccessVpnVO vpnVO, Long accountId, List addUsers, List removeUsers); - + boolean addRemoveVpnUsers(RemoteAccessVpnVO vpnVO, List addUsers, List removeUsers); boolean deleteRemoteAccessVpn(RemoteAccessVpnVO vpnVO); diff --git a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java index 1d288f481a6..3d17e31e4cc 100644 --- a/server/src/com/cloud/network/router/DomainRouterManagerImpl.java +++ b/server/src/com/cloud/network/router/DomainRouterManagerImpl.java @@ -2266,7 +2266,7 @@ public class DomainRouterManagerImpl implements DomainRouterManager, VirtualMach } @Override - public boolean addRemoveVpnUsers(RemoteAccessVpnVO vpnVO, Long accountId, List addUsers, List removeUsers) { + public boolean addRemoveVpnUsers(RemoteAccessVpnVO vpnVO, List addUsers, List removeUsers) { DomainRouterVO router = getRouter(vpnVO.getAccountId(), vpnVO.getZoneId()); if (router == null) { s_logger.warn("Failed to add/remove VPN users: no router found for account and zone");