nl.strohalm.cyclos.webservices.interceptor.AuthInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for nl.strohalm.cyclos.webservices.interceptor.AuthInterceptor.java

Source

/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
    
Cyclos 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 2 of the License, or
(at your option) any later version.
    
Cyclos 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 Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    
 */
package nl.strohalm.cyclos.webservices.interceptor;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;

import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.services.ServiceClient;
import nl.strohalm.cyclos.entities.services.ServiceOperation;
import nl.strohalm.cyclos.services.application.ApplicationServiceLocal;
import nl.strohalm.cyclos.services.services.ServiceClientServiceLocal;
import nl.strohalm.cyclos.utils.access.LoggedUser;
import nl.strohalm.cyclos.webservices.CyclosWebServicesClientFactory;
import nl.strohalm.cyclos.webservices.Permission;
import nl.strohalm.cyclos.webservices.WebServiceContext;
import nl.strohalm.cyclos.webservices.WebServiceContext.ContextType;
import nl.strohalm.cyclos.webservices.WebServiceFaultsEnum;
import nl.strohalm.cyclos.webservices.utils.WebServiceHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.cxf.binding.soap.SoapFault;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.transport.http.AbstractHTTPDestination;

/**
 * A CXF interceptor that will process authentication & authorization for web services
 * 
 * @author luis
 */
public class AuthInterceptor extends AbstractSoapInterceptor {

    private static final String[] BLANK_CREDENTIALS = { "", "" };

    private ServiceClientServiceLocal serviceClientServiceLocal;
    private ApplicationServiceLocal applicationServiceLocal;

    private final Map<QName, ServiceOperation[]> cachedOperations = new HashMap<QName, ServiceOperation[]>();

    public AuthInterceptor() {
        super(Phase.PRE_INVOKE);
    }

    @Override
    public void handleMessage(final SoapMessage message) throws Fault {
        final HttpServletRequest request = WebServiceHelper.requestOf(message);
        request.setAttribute(ContextType.class.getName(), ContextType.SERVICE_CLIENT);
        ServiceClient client = null;
        final ServletContext servletContext = servletContextOf(message);
        try {
            if (!applicationServiceLocal.isOnline()) {
                throw WebServiceHelper.fault(WebServiceFaultsEnum.APPLICATION_OFFLINE);
            }

            // Check non-secure access when HTTP is enabled
            if (Boolean.TRUE.equals(servletContext.getAttribute("cyclos.httpEnabled"))) {
                final String protocol = StringUtils.split(request.getRequestURL().toString(), "://")[0];
                if (!"https".equalsIgnoreCase(protocol)) {
                    throw WebServiceHelper.fault(WebServiceFaultsEnum.SECURE_ACCESS_REQUIRED);
                }
            }

            boolean allowed = false;
            // Find the service client
            client = resolveClient(request);
            if (client != null) {
                // Find the requested operation
                final ServiceOperation[] operations = resolveOperations(message);
                if (operations.length == 0) {
                    // When there are no operations, access is granted to anyone
                    allowed = true;
                } else {
                    // Check whether the client has access to the requested operation
                    final Set<ServiceOperation> permissions = client.getPermissions();
                    for (final ServiceOperation serviceOperation : operations) {
                        if (permissions.contains(serviceOperation)) {
                            allowed = true;
                            break;
                        }
                    }
                }
            }
            if (!allowed) {
                throw WebServiceHelper.fault(WebServiceFaultsEnum.UNAUTHORIZED_ACCESS);
            }

            // Initialize the logged user
            LoggedUser.init(client, request.getRemoteAddr(), null);

            // Initialize the context
            WebServiceContext.set(client, servletContext, request, message);
        } catch (Exception e) {
            WebServiceHelper.initializeContext(message);
            if (e instanceof SoapFault) {
                throw (SoapFault) e;
            } else {
                throw WebServiceHelper.fault(e);
            }
        }
    }

    public void setApplicationServiceLocal(final ApplicationServiceLocal applicationService) {
        applicationServiceLocal = applicationService;
    }

    public void setServiceClientServiceLocal(final ServiceClientServiceLocal serviceClientService) {
        serviceClientServiceLocal = serviceClientService;
    }

    /**
     * Find a matching {@link ServiceClient} for the given request
     */
    private ServiceClient resolveClient(final HttpServletRequest request) {
        final String address = request.getRemoteAddr();
        String[] credentials = WebServiceHelper.getCredentials(request);
        if (credentials == null) {
            credentials = BLANK_CREDENTIALS;
        }
        try {
            return serviceClientServiceLocal.findByAddressAndCredentials(address, credentials[0], credentials[1]);
        } catch (final EntityNotFoundException e) {
            return null;
        }
    }

    /**
     * Resolve the possible operations for the current request
     */
    private ServiceOperation[] resolveOperations(final SoapMessage message) {
        final MessageInfo messageInfo = message.get(MessageInfo.class);
        final OperationInfo operation = messageInfo.getOperation();
        final QName operationQName = operation.getName();
        // Try to find the operations in the cache
        ServiceOperation[] operations = cachedOperations.get(operationQName);
        if (operations == null) {
            // Cache miss... find the interface method
            final String operationName = operationQName.getLocalPart();
            final String serviceName = operation.getInterface().getService().getName().getLocalPart();
            final Class<?> serviceInterface = CyclosWebServicesClientFactory.serviceInterfaceForName(serviceName);
            for (final Method m : serviceInterface.getMethods()) {
                if (m.getName().equals(operationName)) {
                    final Permission permission = m.getAnnotation(Permission.class);
                    operations = permission == null ? new ServiceOperation[0] : permission.value();
                    break;
                }
            }
            // Store the operations on the cache for further access
            cachedOperations.put(operationQName, operations);
        }
        return operations;
    }

    /**
     * Returns the SessionContext instance for the given SOAP message
     */
    private ServletContext servletContextOf(final SoapMessage message) {
        return (ServletContext) message.get(AbstractHTTPDestination.HTTP_CONTEXT);
    }
}