org.wso2.carbon.device.mgt.input.adapter.http.HTTPMessageServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.device.mgt.input.adapter.http.HTTPMessageServlet.java

Source

/*
 * Copyright (c) 2005 - 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * 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.wso2.carbon.device.mgt.input.adapter.http;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.input.adapter.http.authorization.DeviceAuthorizer;
import org.wso2.carbon.device.mgt.input.adapter.http.internal.InputAdapterServiceDataHolder;
import org.wso2.carbon.device.mgt.input.adapter.http.oauth.OAuthAuthenticator;
import org.wso2.carbon.device.mgt.input.adapter.extension.ContentInfo;
import org.wso2.carbon.device.mgt.input.adapter.extension.ContentTransformer;
import org.wso2.carbon.device.mgt.input.adapter.extension.transformer.DefaultContentTransformer;
import org.wso2.carbon.device.mgt.input.adapter.extension.validator.DefaultContentValidator;
import org.wso2.carbon.device.mgt.input.adapter.http.exception.HTTPContentInitializationException;
import org.wso2.carbon.device.mgt.input.adapter.http.jwt.JWTAuthenticator;
import org.wso2.carbon.device.mgt.input.adapter.http.util.AuthenticationInfo;
import org.wso2.carbon.device.mgt.input.adapter.http.util.HTTPEventAdapterConstants;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterConfiguration;
import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener;
import org.wso2.carbon.device.mgt.input.adapter.extension.ContentValidator;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * This will act as the event reciver.
 */
public class HTTPMessageServlet extends HttpServlet {

    private static final String AUTH_MESSAGE_STORE_AUTHENTICATION_INFO = "AUTH_MESSAGE_STORE_AUTHENTICATION_INFO";
    private static final String AUTH_FAILURE_RESPONSE = "_AUTH_FAILURE_";

    private static Log log = LogFactory.getLog(HTTPMessageServlet.class);

    private static ContentValidator contentValidator;
    private static ContentTransformer contentTransformer;
    private InputEventAdapterListener eventAdaptorListener;
    private int tenantId;
    private String exposedTransports;
    private static JWTAuthenticator jwtAuthenticator;
    private static OAuthAuthenticator oAuthAuthenticator;
    private static DeviceAuthorizer deviceAuthorizer;

    public HTTPMessageServlet(InputEventAdapterListener eventAdaptorListener, int tenantId,
            InputEventAdapterConfiguration eventAdapterConfiguration, Map<String, String> globalProperties) {
        this.eventAdaptorListener = eventAdaptorListener;
        this.tenantId = tenantId;
        this.exposedTransports = eventAdapterConfiguration.getProperties()
                .get(HTTPEventAdapterConstants.EXPOSED_TRANSPORTS);
        String globalContentValidator = globalProperties
                .get(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_TYPE);

        String contentValidatorType = eventAdapterConfiguration.getProperties()
                .get(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_VALIDATOR_TYPE);
        if (globalContentValidator != null && !globalContentValidator.isEmpty()) {
            contentValidatorType = globalContentValidator;
        }
        if (contentValidatorType == null || HTTPEventAdapterConstants.DEFAULT.equals(contentValidatorType)) {
            contentValidator = InputAdapterServiceDataHolder.getInputAdapterExtensionService()
                    .getDefaultContentValidator();
        } else {
            contentValidator = InputAdapterServiceDataHolder.getInputAdapterExtensionService()
                    .getContentValidator(contentValidatorType);
        }

        String contentTransformerClassName = eventAdapterConfiguration.getProperties()
                .get(HTTPEventAdapterConstants.ADAPTER_CONF_CONTENT_TRANSFORMER_CLASSNAME);
        if (contentTransformerClassName == null
                || contentTransformerClassName.equals(HTTPEventAdapterConstants.DEFAULT)) {
            contentTransformer = InputAdapterServiceDataHolder.getInputAdapterExtensionService()
                    .getDefaultContentTransformer();
        } else {
            contentTransformer = InputAdapterServiceDataHolder.getInputAdapterExtensionService()
                    .getContentTransformer(contentValidatorType);
        }

        jwtAuthenticator = new JWTAuthenticator();
        oAuthAuthenticator = new OAuthAuthenticator(globalProperties);
        deviceAuthorizer = new DeviceAuthorizer(globalProperties);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {

        String data = this.inputStreamToString(req.getInputStream());
        if (data == null) {
            log.warn("Event Object is empty/null");
            return;
        }
        AuthenticationInfo authenticationInfo = null;
        if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTPS)) {
            if (!req.isSecure()) {
                res.setStatus(403);
                log.error("Only Secured endpoint is enabled for requests");
                return;
            } else {
                authenticationInfo = this.checkAuthentication(req);
                int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1;
                if (tenantId == -1) {
                    res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
                    res.setStatus(401);
                    log.error("Authentication failed for the request");
                    return;
                } else if (tenantId != this.tenantId) {
                    res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
                    res.setStatus(401);
                    log.error("Authentication failed for the request");
                    return;
                }
            }
        } else if (exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTP)) {
            if (req.isSecure()) {
                res.setStatus(403);
                log.error("Only unsecured endpoint is enabled for requests");
                return;
            }
        } else {
            authenticationInfo = this.checkAuthentication(req);
            int tenantId = authenticationInfo != null ? authenticationInfo.getTenantId() : -1;
            if (tenantId == -1) {
                res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
                res.setStatus(401);
                log.error("Authentication failed for the request");
                return;
            } else if (tenantId != this.tenantId) {
                res.getOutputStream().write(AUTH_FAILURE_RESPONSE.getBytes());
                res.setStatus(401);
                log.error("Authentication failed for the request");
                return;
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Message : " + data);
        }

        if (authenticationInfo != null) {
            Map<String, Object> paramMap = new HashMap<>();
            Enumeration<String> reqParameterNames = req.getParameterNames();
            while (reqParameterNames.hasMoreElements()) {
                String paramterName = reqParameterNames.nextElement();
                paramMap.put(paramterName, req.getParameter(paramterName));
            }
            paramMap.put(HTTPEventAdapterConstants.USERNAME_TAG, authenticationInfo.getUsername());
            paramMap.put(HTTPEventAdapterConstants.TENANT_DOMAIN_TAG, authenticationInfo.getTenantDomain());
            paramMap.put(HTTPEventAdapterConstants.SCOPE_TAG, authenticationInfo.getScopes());
            String deviceId = (String) paramMap.get("deviceId");
            String deviceType = (String) paramMap.get("deviceType");
            if (deviceAuthorizer.isAuthorized(authenticationInfo, deviceId, deviceType)) {
                if (contentValidator != null && contentTransformer != null) {
                    data = (String) contentTransformer.transform(data, paramMap);
                    ContentInfo contentInfo = contentValidator.validate(data, paramMap);
                    if (contentInfo != null && contentInfo.isValidContent()) {
                        HTTPEventAdapter.executorService.submit(new HTTPRequestProcessor(eventAdaptorListener,
                                (String) contentInfo.getMessage(), tenantId));
                    }
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("Unauthorized device with device id" + deviceId + " and device type" + deviceType);
                }
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        doPost(req, res);
    }

    public class HTTPRequestProcessor implements Runnable {

        private InputEventAdapterListener inputEventAdapterListener;
        private String payload;
        private int tenantId;

        public HTTPRequestProcessor(InputEventAdapterListener inputEventAdapterListener, String payload,
                int tenantId) {
            this.inputEventAdapterListener = inputEventAdapterListener;
            this.payload = payload;
            this.tenantId = tenantId;
        }

        public void run() {
            try {
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(tenantId, true);
                if (log.isDebugEnabled()) {
                    log.debug("Event received in HTTP Event Adapter - " + payload);
                }
                if (payload != null) {
                    inputEventAdapterListener.onEvent(payload);
                } else {
                    log.warn("Dropping the empty/null event received through http adapter");
                }
            } catch (Exception e) {
                log.error("Error while parsing http request for processing: " + e.getMessage(), e);
            } finally {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
    }

    private AuthenticationInfo checkAuthentication(HttpServletRequest req) {
        AuthenticationInfo authenticationInfo = (AuthenticationInfo) req.getSession()
                .getAttribute(AUTH_MESSAGE_STORE_AUTHENTICATION_INFO);
        if (authenticationInfo != null) {
            return authenticationInfo;
        }
        if (jwtAuthenticator.isJWTHeaderExist(req)) {
            authenticationInfo = jwtAuthenticator.authenticate(req);
        } else {
            authenticationInfo = oAuthAuthenticator.authenticate(req);
        }
        if (authenticationInfo != null) {
            boolean success = authenticationInfo.isAuthenticated();
            if (success) {
                req.getSession().setAttribute(AUTH_MESSAGE_STORE_AUTHENTICATION_INFO, authenticationInfo);
            }
        }
        return authenticationInfo;
    }

    private String inputStreamToString(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int i;
        while ((i = in.read(buff)) > 0) {
            out.write(buff, 0, i);
        }
        out.close();
        return out.toString();
    }

}