@Override public Pair<List<? extends VpnUser>, Integer> searchForVpnUsers(ListVpnUsersCmd cmd) { String username = cmd.getUsername(); Long id = cmd.getId(); Account caller = CallContext.current().getCallingAccount(); List<Long> permittedAccounts = new ArrayList<Long>(); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>( cmd.getDomainId(), cmd.isRecursive(), null); _accountMgr.buildACLSearchParameters( caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); Filter searchFilter = new Filter(VpnUserVO.class, "username", true, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchBuilder<VpnUserVO> sb = _vpnUsersDao.createSearchBuilder(); _accountMgr.buildACLSearchBuilder( sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); sb.and("username", sb.entity().getUsername(), SearchCriteria.Op.EQ); sb.and("state", sb.entity().getState(), Op.IN); SearchCriteria<VpnUserVO> sc = sb.create(); _accountMgr.buildACLSearchCriteria( sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); // list only active users sc.setParameters("state", State.Active, State.Add); if (id != null) { sc.setParameters("id", id); } if (username != null) { sc.setParameters("username", username); } Pair<List<VpnUserVO>, Integer> result = _vpnUsersDao.searchAndCount(sc, searchFilter); return new Pair<List<? extends VpnUser>, Integer>(result.first(), result.second()); }
@Override public List<? extends VpnUser> listVpnUsers(long vpnOwnerId, String userName) { Account caller = CallContext.current().getCallingAccount(); Account owner = _accountDao.findById(vpnOwnerId); _accountMgr.checkAccess(caller, null, true, owner); return _vpnUsersDao.listByAccount(vpnOwnerId); }
@DB @Override public boolean removeVpnUser(long vpnOwnerId, String username, Account caller) { final VpnUserVO user = _vpnUsersDao.findByAccountAndUsername(vpnOwnerId, username); if (user == null) { throw new InvalidParameterValueException("Could not find vpn user " + username); } _accountMgr.checkAccess(caller, null, true, user); Transaction.execute( new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { user.setState(State.Revoke); _vpnUsersDao.update(user.getId(), user); UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } }); return true; }
@Override @DB public VpnUser addVpnUser(long vpnOwnerId, String username, String password) { Account caller = UserContext.current().getCaller(); if (!username.matches("^[a-zA-Z0-9][a-zA-Z0-9@._-]{2,63}$")) { throw new InvalidParameterValueException( "Username has to be begin with an alphabet have 3-64 characters including alphabets, numbers and the set '@.-_'"); } if (!password.matches("^[a-zA-Z0-9][a-zA-Z0-9@#+=._-]{2,31}$")) { throw new InvalidParameterValueException( "Password has to be 3-32 characters including alphabets, numbers and the set '@#+=.-_'"); } Transaction txn = Transaction.currentTxn(); txn.start(); Account owner = _accountDao.lockRow(vpnOwnerId, true); if (owner == null) { throw new InvalidParameterValueException("Unable to add vpn user: Another operation active"); } _accountMgr.checkAccess(caller, null, true, owner); // don't allow duplicated user names for the same account VpnUserVO vpnUser = _vpnUsersDao.findByAccountAndUsername(owner.getId(), username); if (vpnUser != null) { throw new InvalidParameterValueException( "VPN User with name " + username + " is already added for account " + owner); } long userCount = _vpnUsersDao.getVpnUserCount(owner.getId()); if (userCount >= _userLimit) { throw new AccountLimitException( "Cannot add more than " + _userLimit + " remote access vpn users"); } VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, owner.getDomainId(), username, password)); UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); txn.commit(); return user; }
@Override @DB public RemoteAccessVpnVO startRemoteAccessVpn(long vpnId, boolean openFirewall) throws ResourceUnavailableException { Account caller = UserContext.current().getCaller(); RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(vpnId); if (vpn == null) { throw new InvalidParameterValueException("Unable to find your vpn: " + vpnId); } _accountMgr.checkAccess(caller, null, true, vpn); Network network = _networkMgr.getNetwork(vpn.getNetworkId()); boolean started = false; try { boolean firewallOpened = true; if (openFirewall) { firewallOpened = _firewallMgr.applyIngressFirewallRules(vpn.getServerAddressId(), caller); } if (firewallOpened) { for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) { if (element.startVpn(network, vpn)) { started = true; break; } } } return vpn; } finally { if (started) { Transaction txn = Transaction.currentTxn(); txn.start(); vpn.setState(RemoteAccessVpn.State.Running); _remoteAccessVpnDao.update(vpn.getServerAddressId(), vpn); // Start billing of existing VPN users in ADD and Active state List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); for (VpnUserVO user : vpnUsers) { if (user.getState() != VpnUser.State.Revoke) { UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } txn.commit(); } } }
@DB @Override public boolean removeVpnUser(long vpnOwnerId, String username, Account caller) { VpnUserVO user = _vpnUsersDao.findByAccountAndUsername(vpnOwnerId, username); if (user == null) { throw new InvalidParameterValueException("Could not find vpn user " + username); } _accountMgr.checkAccess(caller, null, true, user); Transaction txn = Transaction.currentTxn(); txn.start(); user.setState(State.Revoke); _vpnUsersDao.update(user.getId(), user); UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); txn.commit(); return true; }
@DB @Override public boolean applyVpnUsers(long vpnOwnerId, String userName) { Account caller = CallContext.current().getCallingAccount(); Account owner = _accountDao.findById(vpnOwnerId); _accountMgr.checkAccess(caller, null, true, owner); s_logger.debug("Applying vpn users for " + owner); List<RemoteAccessVpnVO> vpns = _remoteAccessVpnDao.findByAccount(vpnOwnerId); List<VpnUserVO> users = _vpnUsersDao.listByAccount(vpnOwnerId); // If user is in Active state, we still have to resend them therefore their status has to be Add for (VpnUserVO user : users) { if (user.getState() == State.Active) { user.setState(State.Add); _vpnUsersDao.update(user.getId(), user); } } boolean success = true; boolean[] finals = new boolean[users.size()]; for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) { s_logger.debug("Applying vpn access to " + element.getName()); for (RemoteAccessVpnVO vpn : vpns) { try { String[] results = element.applyVpnUsers(vpn, users); if (results != null) { for (int i = 0; i < results.length; i++) { s_logger.debug( "VPN User " + users.get(i) + (results[i] == null ? " is set on " : (" couldn't be set due to " + results[i]) + " on ") + vpn); if (results[i] == null) { if (!finals[i]) { finals[i] = true; } } else { finals[i] = false; success = false; } } } } catch (Exception e) { s_logger.warn("Unable to apply vpn users ", e); success = false; for (int i = 0; i < finals.length; i++) { finals[i] = false; } } } } for (int i = 0; i < finals.length; i++) { final VpnUserVO user = users.get(i); if (finals[i]) { if (user.getState() == State.Add) { user.setState(State.Active); _vpnUsersDao.update(user.getId(), user); } else if (user.getState() == State.Revoke) { _vpnUsersDao.remove(user.getId()); } } else { if (user.getState() == State.Add && (user.getUsername()).equals(userName)) { Transaction.execute( new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { _vpnUsersDao.remove(user.getId()); UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } }); } s_logger.warn( "Failed to apply vpn for user " + user.getUsername() + ", accountId=" + user.getAccountId()); } } return success; }
@Override @DB public void destroyRemoteAccessVpn(long ipId, Account caller) throws ResourceUnavailableException { RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(ipId); if (vpn == null) { s_logger.debug("vpn id=" + ipId + " does not exists "); return; } _accountMgr.checkAccess(caller, null, true, vpn); Network network = _networkMgr.getNetwork(vpn.getNetworkId()); vpn.setState(RemoteAccessVpn.State.Removed); _remoteAccessVpnDao.update(vpn.getServerAddressId(), vpn); boolean success = false; try { for (RemoteAccessVPNServiceProvider element : _vpnServiceProviders) { if (element.stopVpn(network, vpn)) { success = true; break; } } } finally { if (success) { // Cleanup corresponding ports List<? extends FirewallRule> vpnFwRules = _rulesDao.listByIpAndPurpose(ipId, Purpose.Vpn); Transaction txn = Transaction.currentTxn(); boolean applyFirewall = false; List<FirewallRuleVO> fwRules = new ArrayList<FirewallRuleVO>(); // if related firewall rule is created for the first vpn port, it would be created for the 2 // other ports as well, so need to cleanup the backend if (_rulesDao.findByRelatedId(vpnFwRules.get(0).getId()) != null) { applyFirewall = true; } if (applyFirewall) { txn.start(); for (FirewallRule vpnFwRule : vpnFwRules) { // don't apply on the backend yet; send all 3 rules in a banch _firewallMgr.revokeRelatedFirewallRule(vpnFwRule.getId(), false); fwRules.add(_rulesDao.findByRelatedId(vpnFwRule.getId())); } s_logger.debug( "Marked " + fwRules.size() + " firewall rules as Revoked as a part of disable remote access vpn"); txn.commit(); // now apply vpn rules on the backend s_logger.debug( "Reapplying firewall rules for ip id=" + ipId + " as a part of disable remote access vpn"); success = _firewallMgr.applyIngressFirewallRules(ipId, caller); } if (success) { try { txn.start(); _remoteAccessVpnDao.remove(ipId); // Stop billing of VPN users when VPN is removed. VPN_User_ADD events will be generated // when VPN is created again List<VpnUserVO> vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); for (VpnUserVO user : vpnUsers) { // VPN_USER_REMOVE event is already generated for users in Revoke state if (user.getState() != VpnUser.State.Revoke) { UsageEventUtils.publishUsageEvent( EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } if (vpnFwRules != null) { for (FirewallRule vpnFwRule : vpnFwRules) { _rulesDao.remove(vpnFwRule.getId()); s_logger.debug( "Successfully removed firewall rule with ip id=" + vpnFwRule.getSourceIpAddressId() + " and port " + vpnFwRule.getSourcePortStart() + " as a part of vpn cleanup"); } } txn.commit(); } catch (Exception ex) { txn.rollback(); s_logger.warn("Unable to release the three vpn ports from the firewall rules", ex); } } } } }