/*******************************************************************************
* Copyright 2012 I3M-GRyCAP
*
* Licensed 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 org.grycap.vmrc.ws;
import java.util.List;
import javax.annotation.Resource;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.WebServiceContext;
import org.apache.log4j.Logger;
import org.grycap.vmrc.entity.Application;
import org.grycap.vmrc.entity.User;
import org.grycap.vmrc.entity.VMI;
import org.grycap.vmrc.exceptions.ServiceException;
import org.grycap.vmrc.model.VMIOperation;
import org.grycap.vmrc.repository.transfer.FTPSession;
import org.grycap.vmrc.repository.transfer.FTPSessionManager;
import org.grycap.vmrc.repository.transfer.FTPTransferParams;
import org.grycap.vmrc.service.SecurityService;
import org.grycap.vmrc.service.VMIService;
import org.grycap.vmrc.utils.parsing.VMIDescriptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
/**
*
* VMRC Web Service implementation
*
*/
@WebService
@SOAPBinding(style = Style.DOCUMENT)
@Transactional
public class VMRCImpl extends SpringBeanAutowiringSupport {
private static final Logger log = Logger.getLogger(VMRCImpl.class);
@Autowired
private VMIService vmiService;
@Autowired
private SecurityService securityService;
@Resource
private WebServiceContext webServiceContext;
FTPSessionManager ftpSessionManager;
public VMRCImpl(){
initVMRC();
}
private void initVMRC(){
// log.info("AFTER INJECTION: vmiService " + vmiService);
//None at the moment
}
/**************************************************************************
* ============ USER OPERATIONS =======================================
**************************************************************************/
/**
* Register a new VMI in the catalog
* @param vmi
* @return
* @throws Exception
*/
public VMI addVMIByObject(@WebParam(name = "vmi") VMI vmi) throws Exception {
try {
log.info("Invoked addVMIByObject with VMI: " + vmi);
checkCredentials();
checkOperationCredentials(VMIOperation.ADD, vmi);
VMI result = vmiService.saveOrUpdate(vmi);
log.info("Successfully saved VMI : " + result);
return result;
} catch (Exception e) {
log.error(e);
throw e;
}
}
/**
* Registers a new VMI in the catalog
* @param vmiDescStr The VMI descriptor
* @return The registered VMI
* @throws Exception
*/
public VMI addVMI(@WebParam(name = "vmiDescStr") String vmiDescStr) throws Exception {
try {
log.info("Invoked addVMIByDescriptor with VMI descriptor " + vmiDescStr);
checkCredentials();
VMIDescriptor vmiDescriptor = new VMIDescriptor();
VMI vmi = vmiDescriptor.parseVMIFromString(vmiDescStr);
User user = securityService.getUserFromContext(webServiceContext);
vmi.setOwner(user.getUserName());
log.debug("Parsed VMI descriptor into VMI " + vmi);
//checkOperationCredentials(VMIOperation.ADD, vmi);
if (vmiService.getByName(vmi.getName()) != null){
String msg = "The VMI " + vmi.getName() + " already exists in VMRC.";
log.error(msg);
throw new ServiceException(msg);
}
vmiService.saveOrUpdate(vmi);
log.info("Successfully performed addVMIByDescriptor");
return vmi;
} catch (Exception e) {
log.error("Problems while invoking addVMI: " + e);
throw e;
}
}
/**
* Search the list of VMIs that match the requirements specified by the VMI descriptor
* @param vmiDescStr The VMI descriptor
* @return The list of candidate VMIs
* @throws Exception
*/
public List<VMI> search(@WebParam(name = "vmiDescStr") String vmiDescStr) throws Exception{
try {
if (vmiDescStr == null || vmiDescStr.equals("")) return list();
log.info("Invoked SEARCH with VMI descriptor: " + vmiDescStr);
checkCredentials();
VMIDescriptor vmiDescriptor = new VMIDescriptor();
vmiDescriptor.parseFromString(vmiDescStr);
User user = securityService.getUserFromContextFromDatabase(webServiceContext);
log.info("Performing SEARCH with user: " + user);
List<VMI> l = vmiService.searchVMIs(vmiDescriptor, user);
log.info("Successfully performed SEARCH. Obtained list of VMIs: " + l);
return l;
} catch (Exception e) {
log.error("Problems while invoking SEARCH: "+ e);
throw e;
}
}
/**
* Lists the VMIs registered in the catalog (those whose ACL allow listing)
* @return The list of VMIs
* @throws Exception
*/
public List<VMI> list() throws Exception {
try {
log.info("Invoked LIST");
checkCredentials();
List<VMI> l = vmiService.getListCheckingACL(securityService.getUserFromContextFromDatabase(webServiceContext));
log.debug("Successfully performed LIST. Obtained list of VMIs: " + l);
return l;
} catch (Exception e) {
e.printStackTrace();
log.error("Problems while invoking LIST: "+ e);
throw new Exception(e);
}
}
/**
* List the registered applications. This allows the user to know the application names
* already employed, in order to avoid a mess with the naming of the applications.
* @return
* @throws Exception
*/
public List<Application> listApplications() throws Exception{
try{
log.info("Invoked LIST APPLICATIONS");
checkCredentials();
List<Application> l = vmiService.listApplications();
log.debug("Successfully performed LIST APPLICATIONS. Obtained list of Applications: " + l);
return l;
}catch(Exception e){
log.error("Problems while invoking LIST APPLICATIONS: " + e);
throw new Exception(e);
}
}
/**
* Delete a VMI from the catalog
* @param vmiName The name of the VMI
* @throws Exception
*/
public void delete(@WebParam(name = "vmiName") String vmiName) throws Exception {
try {
log.info("Invoked DELETE of VMI " + vmiName);
checkCredentials();
VMI vmi = vmiService.getByName(vmiName);
checkOperationCredentials(VMIOperation.DELETE, vmi);
vmiService.deleteByName(vmiName);
} catch (Exception e) {
log.error(e);
throw new Exception("Error deleting VMI with name " + vmiName, e);
}
}
/**
* Obtain the OVF-compliant XML representation of a VMI
* @param vmiName
* @return
* @throws Exception
*/
public String getOVFByVMI(@WebParam(name = "vmiName") String vmiName) throws Exception{
try{
log.info("Invoked GETOVF for VMI " + vmiName);
checkCredentials();
VMI vmi = vmiService.getByName(vmiName);
String ovf = vmi.toOVF();
log.info("Successsfully performed GETOVF for VMI " + vmiName);
return ovf;
}catch(Exception e){
log.error(e);
throw e;
}
}
/**
* Modify the ACL of a VMI to specify a given perm (all|owner) to a given operation (add|list|upload|search|download|remove)
* @param vmiName
* @param operation
* @param user
* @throws Exception
*/
public void changeVMIAcl(@WebParam(name = "vmiName") String vmiName, @WebParam(name = "operation") String operation, @WebParam(name = "perm") String perm) throws Exception {
try {
log.debug("Invoked CHANGE_VMI_ACL for VMI " + vmiName + ", operation " + operation + " with perm " + perm);
VMI vmi = vmiService.getByName(vmiName);
checkOwnerCredentialsOrAdmin(vmi);
securityService.changeVMIAcl(vmiName, operation, perm);
log.debug("Successfully performed CHANGE_VMI_ACL for VMI " + vmiName);
} catch (Exception e) {
log.error(e);
throw new Exception(e.getMessage());
}
}
/**
* Request to upload a VMI. This causes a temporary FTP server to be fired up in order for the client to perform the
* data transfer.
* @param vmiName The name of the VMI
* @param vmiFileName
* @return The FTP connection details
* @throws Exception
*/
public FTPTransferParams requestToUploadVMI(@WebParam(name = "vmiName") String vmiName, @WebParam(name = "vmiFileName") String vmiFileName) throws Exception {
try {
checkCredentials();
log.info("Invoked requestToUploadVMI with VMI " + vmiName + " for file: " + vmiFileName);
VMI vmi = vmiService.getByName(vmiName);
if (vmi == null){
String msg = "The VMI " + vmiName + " does not exist.";
log.error(msg);
throw new ServiceException(msg);
}
checkOperationCredentials(VMIOperation.UPLOAD, vmi);
if (ftpSessionManager == null){
log.debug("Creating new FTPSessionManager");
ftpSessionManager = new FTPSessionManager();
}
log.debug("Creating new FTPSession to store " + vmiFileName + " for VMI " + vmiName);
FTPSession ftpSession = ftpSessionManager.createNewFTPUploadSession(vmiName, vmiFileName);
FTPTransferParams ftpSessionParams = ftpSession.getTransferParameters();
vmi.setLocation(ftpSessionParams.getPath());
vmiService.saveOrUpdate(vmi); //Is this necessary?
log.debug("Sucessfully performed requestToUploadVMI. Obtained FTP transfer params: " + ftpSessionParams);
return ftpSessionParams;
} catch (Exception e) {
log.error(e);
throw new Exception(e.getMessage());
}
}
/**
* Request to download a VMI
* @param vmiName
* @return The FTP connection details
* @throws Exception
*/
public FTPTransferParams requestToDownloadVMI(@WebParam(name = "vmiName") String vmiName) throws Exception{
try{
checkCredentials();
log.info("Invoked requestToDownloadVMI with name " + vmiName);
VMI vmi = vmiService.getByName(vmiName);
if (vmi == null){
String msg = "The VMI " + vmiName + " does not exist.";
log.error(msg);
throw new ServiceException(msg);
}
checkOperationCredentials(VMIOperation.DOWNLOAD, vmi);
if (ftpSessionManager == null){
log.debug("Creating new FTPSessionManager");
ftpSessionManager = new FTPSessionManager();
}
log.debug("Creating new FTPSession to download VMI " + vmiName);
FTPSession ftpSession = ftpSessionManager.createNewFTPDownloadSession(vmiName);
FTPTransferParams ftpTransferParams = ftpSession.getTransferParameters();
log.info("Successfully performed requestToDownladVMI with name " + vmiName);
return ftpTransferParams;
}catch(Exception e){
log.error(e);
throw new Exception(e.getMessage());
}
}
/**************************************************************************
* ============ ADMIN OPERATIONS =======================================
**************************************************************************/
/**
* List users
*
* @throws Exception
*/
public List<User> listUsers() throws Exception {
try {
log.info("Invoked LIST_USERS");
checkAdminCredentials();
List<User> l = this.securityService.listUsers();
log.info("Successfully performed LIST_USERS. Obtained: " + l);
return l;
} catch (Exception e) {
String msg = "Error listing users. Reason: " + e.getMessage();
log.error(msg);
throw new Exception(msg, e);
}
}
public User listUser(@WebParam(name = "userName") String userName) throws Exception{
try {
log.info("Invoked LIST_USER with " + userName);
checkAdminCredentials();
User u = this.securityService.findUserByName(userName);
log.info("Successfully performed LIST_USER. Obtained: " + u);
return u;
} catch (Exception e) {
String msg = "Error listing user. Reason: " + e.getMessage();
log.error(msg);
throw new Exception(msg, e);
}
}
/**
* Add a new User to the catalog. Only the admin user is allowed to do it.
* @param userName
* @param userPassword
* @throws Exception
*/
public User addUser(@WebParam(name = "userName") String userName, @WebParam(name = "userPassword") String userPassword) throws Exception {
try {
log.info("Invoked ADDUSER with (" + userName + "," + userPassword + ")");
checkAdminCredentials();
User u = securityService.addUser(userName, userPassword);
log.info("Successfully performed ADDUSER with (" + userName + "," + userPassword + ")");
return u;
} catch (Exception e) {
String msg = "Error creating new user. Reason: " + e.getMessage();
log.error(msg);
throw new Exception(msg, e);
}
}
/**
* Delete user from the catalog. No related VMIs will be removed. The ownership of the VMIs will not
* be altered.
* @param userName
* @param userPassword
* @throws Exception
*/
public void deleteUser(@WebParam(name = "userName") String userName) throws Exception {
try {
log.info("Invoked DELETEUSER for " + userName);
checkAdminCredentials();
securityService.deleteUser(userName);
log.info("Successfully performed DELETEUSER");
} catch (Exception e) {
String msg = "Error deleting user. Reason: " + e.getMessage();
log.error(msg);
throw new Exception(msg, e);
}
}
public void changeUserAcl(@WebParam(name = "userName") String userName, @WebParam(name = "operation") String operation, @WebParam(name = "perm") String perm) throws Exception {
try {
log.debug("Invoked CHANGEUSERACL for user " + userName + ", operation " + operation + " with perm " + perm);
checkAdminCredentials();
securityService.changeUserAcl(userName, operation, perm);
log.debug("Successfully performed CHANGEUSERACL");
} catch (Exception e) {
String msg = "Error changing User ACL. Reason: "+ e.getMessage();
log.error(msg);
throw new Exception(msg,e);
}
}
/**************************************************************************
* ============ AUXILIARY OPERATIONS =======================================
**************************************************************************/
private void checkCredentials() throws ServiceException, Exception {
if(!securityService.hasValidUserCredentials(webServiceContext)) {
throw new Exception("Unauthorized attempt to perform operation");
}
}
private void checkOwnerCredentialsOrAdmin(VMI vmi) throws ServiceException, Exception {
if(!securityService.isOwnerOfVMIOrAdmin(vmi,webServiceContext)) {
throw new Exception("Unauthorized attempt to perform operation");
}
}
private void checkOperationCredentials(VMIOperation operation, VMI vmi) throws ServiceException, Exception {
if(!securityService.checkOperationCredentials(operation, vmi, webServiceContext)) {
throw new Exception("Unauthorized attempt of performing operation " + operation.getOperationName() + " to VMI " + vmi.getName());
}
}
private void checkAdminCredentials() throws ServiceException, Exception {
if(!securityService.hasValidAdminUserCredentials(webServiceContext)) {
throw new Exception("Unauthorized attempt of invoking method: Admin user required");
}
}
}