/* * 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.event.input.adapter.http; import org.apache.axiom.om.util.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.event.input.adapter.core.InputEventAdapterListener; import org.wso2.carbon.event.input.adapter.http.internal.ds.HTTPEventAdapterServiceValueHolder; import org.wso2.carbon.event.input.adapter.http.internal.util.HTTPEventAdapterConstants; import org.wso2.carbon.user.api.UserStoreManager; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; 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; public class HTTPMessageServlet extends HttpServlet { private static final String AUTHORIZATION_HEADER = "Authorization"; private static final String AUTH_MESSAGE_STORE_TENANT_ID = "AUTH_MESSAGE_STORE_TENANT_ID"; private static final String AUTH_FAILURE_RESPONSE = "_AUTH_FAILURE_"; private static Log log = LogFactory.getLog(HTTPMessageServlet.class); private InputEventAdapterListener eventAdaptorListener; private int tenantId; private String exposedTransports; private boolean isBasicAuthEnabled; public HTTPMessageServlet(InputEventAdapterListener eventAdaptorListener, int tenantId, String exposedTransports, boolean isBasicAuthEnabled) { this.eventAdaptorListener = eventAdaptorListener; this.tenantId = tenantId; this.exposedTransports = exposedTransports; this.isBasicAuthEnabled = isBasicAuthEnabled; } private String[] getUserPassword(HttpServletRequest req) { String authHeader = req.getHeader(AUTHORIZATION_HEADER); if (authHeader == null) { return null; } if (!authHeader.startsWith("Basic ")) { return null; } String[] userPassword = new String(Base64.decode(authHeader.substring(6))).split(":"); if (userPassword.length != 2) { return null; } return userPassword; } private int checkAuthentication(HttpServletRequest req) { Object tidObj = req.getSession().getAttribute(AUTH_MESSAGE_STORE_TENANT_ID); if (tidObj != null) { return (Integer) tidObj; } String[] userPassword = this.getUserPassword(req); if (userPassword == null) { return -1; } String username = userPassword[0]; String password = userPassword[1]; String tenantDomain = MultitenantUtils.getTenantDomain(username); String tenantAwareUserName = MultitenantUtils.getTenantAwareUsername(username); username = (tenantAwareUserName + "@" + tenantDomain).toLowerCase(); RealmService realmService = HTTPEventAdapterServiceValueHolder.getRealmService(); int tenantId; try { tenantId = realmService.getTenantManager().getTenantId(tenantDomain); if (tenantId == -1) { return -1; } UserStoreManager usm = realmService.getTenantUserRealm(tenantId).getUserStoreManager(); boolean success = usm.authenticate(tenantAwareUserName, password); if (success) { req.getSession().setAttribute(AUTH_MESSAGE_STORE_TENANT_ID, tenantId); return tenantId; } else { return -1; } } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("checkAuthentication() fail: " + e.getMessage(), e); } return -1; } } 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(); } @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; } if(exposedTransports.equalsIgnoreCase(HTTPEventAdapterConstants.HTTPS)){ if(! req.isSecure()){ res.setStatus(403); log.error("Only Secured endpoint is enabled for requests"); return; }else { if(isBasicAuthEnabled){ int tenantId = this.checkAuthentication(req); 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 { if(req.isSecure()){ if(isBasicAuthEnabled){ int tenantId = this.checkAuthentication(req); 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); } HTTPEventAdapter.executorService.submit(new HTTPRequestProcessor(eventAdaptorListener, data, tenantId)); } @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); if (log.isDebugEnabled()) { log.debug("Event received in HTTP Event Adapter - " + payload); } if (payload.trim() != 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(); } } } }