diff --git a/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java b/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java index 9e640873883..d80bae03b3b 100644 --- a/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java +++ b/core/src/com/cloud/agent/api/routing/VpnUsersCfgCommand.java @@ -60,6 +60,9 @@ public class VpnUsersCfgCommand extends RoutingCommand { protected UsernamePassword() { //for Gson } + public String getUsernamePassword() { + return getUsername() + "," + getPassword(); + } } String vpnAppliancePrivateIpAddress; //router private ip address typically UsernamePassword [] userpwds; @@ -73,10 +76,10 @@ public class VpnUsersCfgCommand extends RoutingCommand { userpwds = new UsernamePassword[addUsers.size() + removeUsers.size()]; int i = 0; for (VpnUserVO vpnUser: removeUsers) { - userpwds[i++] = new UsernamePassword(vpnUser.getUserName(), vpnUser.getPassword(), false); + userpwds[i++] = new UsernamePassword(vpnUser.getUsername(), vpnUser.getPassword(), false); } for (VpnUserVO vpnUser: addUsers) { - userpwds[i++] = new UsernamePassword(vpnUser.getUserName(), vpnUser.getPassword(), true); + userpwds[i++] = new UsernamePassword(vpnUser.getUsername(), vpnUser.getPassword(), true); } } @@ -85,6 +88,10 @@ public class VpnUsersCfgCommand extends RoutingCommand { return true; } + public UsernamePassword[] getUserpwds() { + return userpwds; + } + public String getVpnAppliancePrivateIpAddress() { return vpnAppliancePrivateIpAddress; } diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index da6ca7a6e00..9a0e64117c8 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -1232,11 +1232,18 @@ public abstract class CitrixResourceBase implements StoragePoolResource, ServerR protected synchronized Answer execute(final VpnUsersCfgCommand cmd) { String args = cmd.getRouterPrivateIpAddress(); - - String result = callHostPlugin("vmops", "lt2p_vpn", "args", args); - if (result == null || result.isEmpty()) { - return new Answer(cmd, false, "Configure VPN failed"); - } + for (VpnUsersCfgCommand.UsernamePassword userpwd: cmd.getUserpwds()) { + if (!userpwd.isAdd()) { + args += " -U " + userpwd.getUsername(); + } else { + args += " -u " + userpwd.getUsernamePassword(); + } + String result = callHostPlugin("vmops", "lt2p_vpn", "args", args); + if (result == null || result.isEmpty()) { + return new Answer(cmd, false, "Configure VPN user failed for user " + userpwd.getUsername()); + } + } + return new Answer(cmd); } diff --git a/core/src/com/cloud/network/VpnUserVO.java b/core/src/com/cloud/network/VpnUserVO.java index 82f4cc117a9..8067f6a0400 100644 --- a/core/src/com/cloud/network/VpnUserVO.java +++ b/core/src/com/cloud/network/VpnUserVO.java @@ -28,7 +28,7 @@ import javax.persistence.SecondaryTable; import javax.persistence.Table; @Entity -@Table(name=("vpn_user")) +@Table(name=("vpn_users")) @SecondaryTable(name="account", pkJoinColumns={@PrimaryKeyJoinColumn(name="account_id", referencedColumnName="id")}) public class VpnUserVO { @@ -47,7 +47,7 @@ public class VpnUserVO { private long domainId; @Column(name="username") - private String userName; + private String username; @Column(name="password") private String password; @@ -56,7 +56,7 @@ public class VpnUserVO { public VpnUserVO(long accountId, String userName, String password) { this.accountId = accountId; - this.userName = userName; + this.username = userName; this.password = password; } @@ -72,15 +72,12 @@ public class VpnUserVO { return accountName; } - - - - public String getUserName() { - return userName; + public String getUsername() { + return username; } - public void setUserName(String userName) { - this.userName = userName; + public void setUsername(String userName) { + this.username = userName; } public String getPassword() { diff --git a/core/src/com/cloud/network/dao/VpnUserDaoImpl.java b/core/src/com/cloud/network/dao/VpnUserDaoImpl.java index 52fd4ee4a35..4beed118a97 100644 --- a/core/src/com/cloud/network/dao/VpnUserDaoImpl.java +++ b/core/src/com/cloud/network/dao/VpnUserDaoImpl.java @@ -41,7 +41,7 @@ public class VpnUserDaoImpl extends GenericDaoBase implements V AccountNameSearch = createSearchBuilder(); AccountNameSearch.and("accountId", AccountNameSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - AccountNameSearch.and("userName", AccountNameSearch.entity().getUserName(), SearchCriteria.Op.EQ); + AccountNameSearch.and("username", AccountNameSearch.entity().getUsername(), SearchCriteria.Op.EQ); AccountNameSearch.done(); } @@ -54,9 +54,9 @@ public class VpnUserDaoImpl extends GenericDaoBase implements V @Override public VpnUserVO findByAccountAndUsername(Long accountId, String userName) { - SearchCriteria sc = AccountSearch.create(); + SearchCriteria sc = AccountNameSearch.create(); sc.setParameters("accountId", accountId); - sc.setParameters("userName", userName); + sc.setParameters("username", userName); return findOneBy(sc); } diff --git a/patches/systemvm/debian/vpn/opt/cloud/bin/vpn_l2tp.sh b/patches/systemvm/debian/vpn/opt/cloud/bin/vpn_l2tp.sh index fbb6659ae40..0cb9709e6a6 100755 --- a/patches/systemvm/debian/vpn/opt/cloud/bin/vpn_l2tp.sh +++ b/patches/systemvm/debian/vpn/opt/cloud/bin/vpn_l2tp.sh @@ -76,6 +76,11 @@ destroy_l2tp_ipsec_vpn_server() { remove_l2tp_ipsec_user() { local u=$1 sed -i -e "/^$u .*$/d" /etc/ppp/chap-secrets + if [ -x /usr/bin/tdbdump ]; then + pid=$(tdbdump /var/run/pppd2.tdb | grep -w $u | awk -F';' '{print $4}' | awk -F= '{print $2}') + [ "$pid" != "" ] && kill -9 $pid + fi + } add_l2tp_ipsec_user() { diff --git a/server/src/com/cloud/api/commands/AddVpnUserCmd.java b/server/src/com/cloud/api/commands/AddVpnUserCmd.java index bcb13e6f675..193420cb1d1 100644 --- a/server/src/com/cloud/api/commands/AddVpnUserCmd.java +++ b/server/src/com/cloud/api/commands/AddVpnUserCmd.java @@ -44,7 +44,7 @@ public class AddVpnUserCmd extends BaseAsyncCmd { @Parameter(name="username", type=CommandType.STRING, required=true, description="username for the vpn user") private String userName; - @Parameter(name="password", type=CommandType.STRING, required=false, description="password for the username") + @Parameter(name="password", type=CommandType.STRING, required=true, description="password for the username") private String password; @Parameter(name="account", type=CommandType.STRING, description="an optional account for the vpn user. Must be used with domainId.") diff --git a/server/src/com/cloud/api/commands/ListVpnUsersCmd.java b/server/src/com/cloud/api/commands/ListVpnUsersCmd.java index c2fadd8491e..a2f9f767744 100644 --- a/server/src/com/cloud/api/commands/ListVpnUsersCmd.java +++ b/server/src/com/cloud/api/commands/ListVpnUsersCmd.java @@ -92,7 +92,7 @@ public class ListVpnUsersCmd extends BaseListCmd { for (VpnUserVO vpnUser : vpnUsers) { VpnUsersResponse vpnResponse = new VpnUsersResponse(); vpnResponse.setId(vpnUser.getId()); - vpnResponse.setUsername(vpnUser.getUserName()); + vpnResponse.setUsername(vpnUser.getUsername()); vpnResponse.setAccountName(vpnUser.getAccountName()); Account accountTemp = ApiDBUtils.findAccountById(vpnUser.getAccountId()); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 48b42b5f766..f0290b7c408 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -2746,11 +2746,17 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { } @Override - public boolean addVpnUser(AddVpnUserCmd cmd) throws ConcurrentOperationException { + public boolean addVpnUser(AddVpnUserCmd cmd) throws ConcurrentOperationException, InvalidParameterValueException { 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()); + if (!cmd.getUserName().matches("^[a-zA-Z0-9][a-zA-Z0-9@._-]{2,15}$")) { + throw new InvalidParameterValueException("Username has to be 3-16 characters including alphabets, numbers and the set '@.-_'"); + } + if (!cmd.getPassword().matches("^[a-zA-Z0-9][a-zA-Z0-9@#+=._-]{2,15}$")) { + throw new InvalidParameterValueException("Password has to be 3-16 characters including alphabets, numbers and the set '@#+=.-_'"); + } 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()); @@ -2802,8 +2808,10 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { } else { user = _vpnUsersDao.findByAccountAndUsername(account.getId(), username); if (user == null) { + s_logger.debug("Could not find vpn user " + username); throw new InvalidParameterValueException("Could not find vpn user " + username); } + _vpnUsersDao.remove(user.getId()); removeVpnUsers.add(user); } for (RemoteAccessVpnVO vpn : vpnVOList) { @@ -2812,9 +2820,9 @@ public class NetworkManagerImpl implements NetworkManager, DomainRouterService { return success; } finally { if (success) { - txn.rollback(); - } else { txn.commit(); + } else { + txn.rollback(); } if (locked) { _accountDao.releaseFromLockTable(account.getId()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 04df9d9418d..9bcd02c78be 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -6209,7 +6209,7 @@ public class ManagementServerImpl implements ManagementServer { SearchBuilder sb = _vpnUsersDao.createSearchBuilder(); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); - sb.and("username", sb.entity().getUserName(), SearchCriteria.Op.EQ); + sb.and("username", sb.entity().getUsername(), SearchCriteria.Op.EQ); sb.and("accountId", sb.entity().getAccountId(), SearchCriteria.Op.EQ); if ((accountId == null) && (domainId != null)) {