diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/pom.xml b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/pom.xml
new file mode 100644
index 0000000000..b8133bc6d8
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ apimgt-extensions
+ org.wso2.carbon.devicemgt
+ 1.2.8-SNAPSHOT
+
+ 4.0.0
+
+ org.wso2.carbon.apimgt.handlers
+ WSO2 Carbon - API Security Handler Component
+
+
+
+ org.wso2.carbon
+ org.wso2.carbon.logging
+ ${carbon.kernel.version}
+
+
+ org.apache.synapse
+ synapse-core
+ ${org.apache.synapse.version}
+
+
+ org.apache.ws.security.wso2
+ wss4j
+ ${org.apache.ws.security.wso2.version}
+
+
+ org.wso2.carbon.devicemgt
+ org.wso2.carbon.certificate.mgt.core
+
+
+ org.json.wso2
+ json
+ ${commons-json.version}
+
+
+
+
\ No newline at end of file
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java
new file mode 100644
index 0000000000..f5c5c80056
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers;
+
+import org.apache.axiom.soap.SOAP11Constants;
+import org.apache.axiom.soap.SOAP12Constants;
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.description.HandlerDescription;
+import org.apache.axis2.description.Parameter;
+import org.apache.axis2.engine.Handler;
+import org.apache.axis2.namespace.Constants;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.util.Base64;
+import org.json.JSONObject;
+import org.wso2.carbon.apimgt.handlers.invoker.RESTInvoker;
+import org.wso2.carbon.apimgt.handlers.invoker.RESTResponse;
+import org.wso2.carbon.apimgt.handlers.utils.AuthConstants;
+import org.wso2.carbon.apimgt.handlers.utils.CoreUtils;
+
+import javax.xml.namespace.QName;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AuthenticationHandler implements Handler {
+ private static final Log log = LogFactory.getLog(AuthenticationHandler.class);
+ private static HandlerDescription EMPTY_HANDLER_METADATA = new HandlerDescription("API Security Handler");
+ private HandlerDescription handlerDesc;
+ private ArrayList apiList;
+ private RESTInvoker restInvoker;
+
+ /**
+ * Setting up configurations at the constructor
+ */
+ public AuthenticationHandler() {
+ log.info("Engaging API Security Handler");
+ apiList = CoreUtils.readApiFilterList();
+ restInvoker = new RESTInvoker();
+ this.handlerDesc = EMPTY_HANDLER_METADATA;
+ }
+
+ /**
+ * Handles incoming http/s requests
+ *
+ * @param messageContext
+ * @return response
+ * @throws AxisFault
+ */
+ public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
+ boolean validateRequest = messageContext.getTo() != null;
+
+ if (validateRequest && isSecuredAPI(messageContext)) {
+ String ctxPath = messageContext.getTo().getAddress().trim();
+ CoreUtils.debugLog(log, "Authentication handler invoked by: ", ctxPath);
+ Map, ?> headers = (Map, ?>) messageContext.getProperty(MessageContext.TRANSPORT_HEADERS);
+
+ if (headers.containsKey(AuthConstants.MDM_SIGNATURE)) {
+ String mdmSignature = headers.get(AuthConstants.MDM_SIGNATURE).toString();
+
+ try {
+ CoreUtils.debugLog(log, "Verify Cert:\n", mdmSignature);
+
+ URI dcrUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
+ .getHttpsPort() + "/dynamic-client-web/register");
+ String dcrContent = "{\n" +
+ "\"owner\":\"" + CoreUtils.getUsername() + "\",\n" +
+ "\"clientName\":\"emm\",\n" +
+ "\"grantType\":\"refresh_token password client_credentials\",\n" +
+ "\"tokenScope\":\"default\"\n" +
+ "}";
+ Map drcHeaders = new HashMap();
+ drcHeaders.put("Content-Type", "application/json");
+
+ RESTResponse response = restInvoker.invokePOST(dcrUrl, drcHeaders, null,
+ null, dcrContent);
+ CoreUtils.debugLog(log, "DCR response:", response.getContent());
+ JSONObject jsonResponse = new JSONObject(response.getContent());
+ String clientId = jsonResponse.getString("client_id");
+ String clientSecret = jsonResponse.getString("client_secret");
+
+ URI tokenUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
+ .getHttpsPort() + "/oauth2/token");
+ String tokenContent = "grant_type=password&username=" + CoreUtils.getUsername() + "&password=" +
+ CoreUtils.getPassword() + "&scope=activity-view";
+ String tokenBasicAuth = "Basic " + Base64.encode((clientId + ":" + clientSecret).getBytes());
+ Map tokenHeaders = new HashMap();
+ tokenHeaders.put("Authorization", tokenBasicAuth);
+ tokenHeaders.put("Content-Type", "application/x-www-form-urlencoded");
+
+ response = restInvoker.invokePOST(tokenUrl, tokenHeaders, null,
+ null, tokenContent);
+ CoreUtils.debugLog(log, "Token response:", response.getContent());
+ jsonResponse = new JSONObject(response.getContent());
+ String accessToken = jsonResponse.getString("access_token");
+
+ URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
+ .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios");
+ Map certVerifyHeaders = new HashMap();
+ certVerifyHeaders.put("Authorization", "Bearer " + accessToken);
+ certVerifyHeaders.put("Content-Type", "application/json");
+ String certVerifyContent = "{\n" +
+ "\"pem\":\"" + mdmSignature + "\",\n" +
+ "\"tenantId\": \"-1234\",\n" +
+ "\"serial\":\"\"\n" +
+ "}";
+
+ response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null,
+ null, certVerifyContent);
+ CoreUtils.debugLog(log, "Verify response:", response.getContent());
+
+ if (!response.getContent().contains("invalid")) {
+ return InvocationResponse.CONTINUE;
+ }
+ log.warn("Unauthorized request for api: " + ctxPath);
+ setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!"));
+ return InvocationResponse.SUSPEND;
+
+ } catch (Exception e) {
+ log.error("Error while processing certificate.", e);
+ setFaultCodeAndThrowAxisFault(messageContext, e);
+ return InvocationResponse.SUSPEND;
+ }
+ } else {
+ log.warn("Unauthorized request for api: " + ctxPath);
+ setFaultCodeAndThrowAxisFault(messageContext, new Exception("SSL required"));
+ return InvocationResponse.SUSPEND;
+ }
+ } else {
+ return InvocationResponse.CONTINUE;
+ }
+
+ }
+
+ /**
+ * API filter
+ *
+ * @param messageContext
+ * @return boolean
+ */
+ private boolean isSecuredAPI(MessageContext messageContext) {
+ if (messageContext.getTransportIn() != null &&
+ messageContext.getTransportIn().getName().toLowerCase().equals(AuthConstants.HTTPS)) {
+ for (String path : apiList) {
+ if (messageContext.getTo().getAddress().trim().contains(path)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void setFaultCodeAndThrowAxisFault(MessageContext msgContext, Exception e) throws AxisFault {
+
+ msgContext.setProperty(AuthConstants.SEC_FAULT, Boolean.TRUE);
+ String soapVersionURI = msgContext.getEnvelope().getNamespace().getNamespaceURI();
+ QName faultCode = null;
+ /*
+ * Get the faultCode from the thrown WSSecurity exception, if there is one
+ */
+ if (e instanceof WSSecurityException) {
+ faultCode = ((WSSecurityException) e).getFaultCode();
+ }
+ /*
+ * Otherwise default to InvalidSecurity
+ */
+ if (faultCode == null) {
+ faultCode = new QName(WSConstants.INVALID_SECURITY.getNamespaceURI(),
+ WSConstants.INVALID_SECURITY.getLocalPart(), AuthConstants.WSSE);
+ }
+
+ if (soapVersionURI.equals(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
+
+ throw new AxisFault(faultCode, e.getMessage(), e);
+
+ } else if (soapVersionURI.equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) {
+
+ List subfaultCodes = new ArrayList();
+ subfaultCodes.add(faultCode);
+ throw new AxisFault(Constants.FAULT_SOAP12_SENDER, subfaultCodes, e.getMessage(), e);
+
+ }
+
+ }
+
+ public void cleanup() {
+ }
+
+ public void init(HandlerDescription handlerDescription) {
+ this.handlerDesc = handlerDescription;
+ }
+
+ public void flowComplete(MessageContext messageContext) {
+ }
+
+ public HandlerDescription getHandlerDesc() {
+ return this.handlerDesc;
+ }
+
+ public String getName() {
+ return "API security inflow handler";
+ }
+
+ public Parameter getParameter(String name) {
+ return this.handlerDesc.getParameter(name);
+ }
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTConstants.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTConstants.java
new file mode 100644
index 0000000000..c1d0413a70
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTConstants.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers.invoker;
+
+public class RESTConstants {
+ static String REST_CLIENT_CONFIG_ELEMENT = "restClientConfiguration";
+ static String REST_CLIENT_MAX_TOTAL_CONNECTIONS = "maxTotalConnections";
+ static String REST_CLIENT_MAX_CONNECTIONS_PER_ROUTE = "maxConnectionsPerRoute";
+ static String REST_CLEINT_CONNECTION_TIMEOUT = "connectionTimeout";
+ static String REST_CLEINT_SOCKET_TIMEOUT = "socketTimeout";
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTInvoker.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTInvoker.java
new file mode 100644
index 0000000000..7873a7fc54
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTInvoker.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers.invoker;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.util.AXIOMUtil;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Header;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.util.EntityUtils;
+import org.wso2.carbon.apimgt.handlers.utils.AuthConstants;
+import org.wso2.carbon.apimgt.handlers.utils.CoreUtils;
+import org.wso2.carbon.utils.CarbonUtils;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.Map;
+
+public class RESTInvoker {
+
+ private static final Log log = LogFactory.getLog(RESTInvoker.class);
+
+ private int maxTotalConnections = 100;
+ private int maxTotalConnectionsPerRoute = 100;
+ private int connectionTimeout = 120000;
+ private int socketTimeout = 120000;
+
+ private CloseableHttpClient client = null;
+ private PoolingHttpClientConnectionManager connectionManager = null;
+
+ public RESTInvoker() {
+ configureHttpClient();
+ }
+
+ private void parseConfiguration() {
+ String carbonConfigDirPath = CarbonUtils.getCarbonConfigDirPath();
+ String apiFilterConfigPath = carbonConfigDirPath + File.separator +
+ AuthConstants.AUTH_CONFIGURATION_FILE_NAME;
+ File configFile = new File(apiFilterConfigPath);
+
+ try {
+ String configContent = FileUtils.readFileToString(configFile);
+ OMElement configElement = AXIOMUtil.stringToOM(configContent);
+ Iterator beans = configElement.getChildrenWithName(
+ new QName("http://www.springframework.org/schema/beans", "bean"));
+
+ while (beans.hasNext()) {
+ OMElement bean = (OMElement) beans.next();
+ String beanId = bean.getAttributeValue(new QName(null, "id"));
+ if (beanId.equals(RESTConstants.REST_CLIENT_CONFIG_ELEMENT)) {
+ Iterator beanProps = bean.getChildrenWithName(
+ new QName("http://www.springframework.org/schema/beans", "property"));
+
+ while (beanProps.hasNext()) {
+ OMElement beanProp = (OMElement) beanProps.next();
+ String beanName = beanProp.getAttributeValue(new QName(null, "name"));
+ if (RESTConstants.REST_CLIENT_MAX_TOTAL_CONNECTIONS.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ if (value != null && !value.trim().equals("")) {
+ maxTotalConnections = Integer.parseInt(value);
+ }
+ CoreUtils.debugLog(log, "Max total http connections ", maxTotalConnections);
+ } else if (RESTConstants.REST_CLIENT_MAX_CONNECTIONS_PER_ROUTE.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ if (value != null && !value.trim().equals("")) {
+ maxTotalConnectionsPerRoute = Integer.parseInt(value);
+ }
+ CoreUtils.debugLog(log, "Max total client connections per route ", maxTotalConnectionsPerRoute);
+ } else if (RESTConstants.REST_CLEINT_CONNECTION_TIMEOUT.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ if (value != null && !value.trim().equals("")) {
+ connectionTimeout = Integer.parseInt(value);
+ }
+ } else if (RESTConstants.REST_CLEINT_SOCKET_TIMEOUT.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ if (value != null && !value.trim().equals("")) {
+ socketTimeout = Integer.parseInt(value);
+ }
+ }
+ }
+ }
+ }
+ } catch (XMLStreamException e) {
+ log.error("Error in processing http connection settings, using default settings", e);
+ } catch (IOException e) {
+ log.error("Error in processing http connection settings, using default settings", e);
+ }
+ }
+
+ private void configureHttpClient() {
+
+ parseConfiguration();
+
+ RequestConfig defaultRequestConfig = RequestConfig.custom()
+ .setExpectContinueEnabled(true)
+ .setConnectTimeout(connectionTimeout)
+ .setSocketTimeout(socketTimeout)
+ .build();
+
+ connectionManager = new PoolingHttpClientConnectionManager();
+ connectionManager.setDefaultMaxPerRoute(maxTotalConnectionsPerRoute);
+ connectionManager.setMaxTotal(maxTotalConnections);
+ client = HttpClients.custom()
+ .setConnectionManager(connectionManager)
+ .setDefaultRequestConfig(defaultRequestConfig)
+ .build();
+
+ CoreUtils.debugLog(log, "REST client initialized with ",
+ "maxTotalConnection = ", maxTotalConnections,
+ "maxConnectionsPerRoute = ", maxTotalConnectionsPerRoute,
+ "connectionTimeout = ", connectionTimeout);
+ }
+
+ public void closeHttpClient() {
+ IOUtils.closeQuietly(client);
+ IOUtils.closeQuietly(connectionManager);
+ }
+
+ /**
+ * Invokes the http GET method
+ *
+ * @param uri endpoint/service url
+ * @param requestHeaders header list
+ * @param username username for authentication
+ * @param password password for authentication
+ * @return RESTResponse of the GET request (can be the response body or the response status code)
+ * @throws Exception
+ */
+ public RESTResponse invokeGET(URI uri, Map requestHeaders, String username, String password) throws IOException {
+
+ HttpGet httpGet = null;
+ CloseableHttpResponse response = null;
+ Header[] headers;
+ int httpStatus;
+ String contentType;
+ String output;
+ try {
+ httpGet = new HttpGet(uri);
+ if (requestHeaders != null && !requestHeaders.isEmpty()) {
+ Object keys[] = requestHeaders.keySet().toArray();
+ for (Object header : keys) {
+ httpGet.setHeader(header.toString(), requestHeaders.get(header).toString());
+ }
+ }
+ response = sendReceiveRequest(httpGet, username, password);
+ output = IOUtils.toString(response.getEntity().getContent());
+ headers = response.getAllHeaders();
+ httpStatus = response.getStatusLine().getStatusCode();
+ contentType = response.getEntity().getContentType().getValue();
+ if (log.isTraceEnabled()) {
+ log.trace("Invoked GET " + uri.toString() + " - Response message: " + output);
+ }
+ EntityUtils.consume(response.getEntity());
+ } finally {
+ if (response != null) {
+ IOUtils.closeQuietly(response);
+ }
+ if (httpGet != null) {
+ httpGet.releaseConnection();
+ }
+ }
+ return new RESTResponse(contentType, output, headers, httpStatus);
+ }
+
+
+ public RESTResponse invokePOST(URI uri, Map requestHeaders, String username,
+ String password, String payload) throws IOException {
+
+ HttpPost httpPost = null;
+ CloseableHttpResponse response = null;
+ Header[] headers;
+ int httpStatus;
+ String contentType;
+ String output;
+ try {
+ httpPost = new HttpPost(uri);
+ httpPost.setEntity(new StringEntity(payload));
+ if (requestHeaders != null && !requestHeaders.isEmpty()) {
+ Object keys[] = requestHeaders.keySet().toArray();
+ for (Object header : keys) {
+ httpPost.setHeader(header.toString(), requestHeaders.get(header).toString());
+ }
+ }
+ response = sendReceiveRequest(httpPost, username, password);
+ output = IOUtils.toString(response.getEntity().getContent());
+ headers = response.getAllHeaders();
+ httpStatus = response.getStatusLine().getStatusCode();
+ contentType = response.getEntity().getContentType().getValue();
+ if (log.isTraceEnabled()) {
+ log.trace("Invoked POST " + uri.toString() +
+ " - Input payload: " + payload + " - Response message: " + output);
+ }
+ EntityUtils.consume(response.getEntity());
+ } finally {
+ if (response != null) {
+ IOUtils.closeQuietly(response);
+ }
+ if (httpPost != null) {
+ httpPost.releaseConnection();
+ }
+ }
+ return new RESTResponse(contentType, output, headers, httpStatus);
+ }
+
+ /**
+ * Invokes the http PUT method
+ *
+ * @param uri endpoint/service url
+ * @param requestHeaders header list
+ * @param username username for authentication
+ * @param password password for authentication
+ * @param payload payload body passed
+ * @return RESTResponse of the PUT request (can be the response body or the response status code)
+ * @throws Exception
+ */
+ public RESTResponse invokePUT(URI uri, Map requestHeaders, String username, String password,
+ String payload) throws IOException {
+
+ HttpPut httpPut = null;
+ CloseableHttpResponse response = null;
+ Header[] headers;
+ int httpStatus;
+ String contentType;
+ String output;
+ try {
+ httpPut = new HttpPut(uri);
+ httpPut.setEntity(new StringEntity(payload));
+ if (requestHeaders != null && !requestHeaders.isEmpty()) {
+ Object keys[] = requestHeaders.keySet().toArray();
+ for (Object header : keys) {
+ httpPut.setHeader(header.toString(), requestHeaders.get(header).toString());
+ }
+ }
+ response = sendReceiveRequest(httpPut, username, password);
+ output = IOUtils.toString(response.getEntity().getContent());
+ headers = response.getAllHeaders();
+ httpStatus = response.getStatusLine().getStatusCode();
+ contentType = response.getEntity().getContentType().getValue();
+ if (log.isTraceEnabled()) {
+ log.trace("Invoked PUT " + uri.toString() + " - Response message: " + output);
+ }
+ EntityUtils.consume(response.getEntity());
+ } finally {
+ if (response != null) {
+ IOUtils.closeQuietly(response);
+ }
+ if (httpPut != null) {
+ httpPut.releaseConnection();
+ }
+ }
+ return new RESTResponse(contentType, output, headers, httpStatus);
+ }
+
+ /**
+ * Invokes the http DELETE method
+ *
+ * @param uri endpoint/service url
+ * @param requestHeaders header list
+ * @param username username for authentication
+ * @param password password for authentication
+ * @return RESTResponse of the DELETE (can be the response status code or the response body)
+ * @throws Exception
+ */
+ public RESTResponse invokeDELETE(URI uri, Map requestHeaders, String username, String password) throws IOException {
+
+ HttpDelete httpDelete = null;
+ CloseableHttpResponse response = null;
+ Header[] headers;
+ int httpStatus;
+ String contentType;
+ String output;
+ try {
+ httpDelete = new HttpDelete(uri);
+ if (requestHeaders != null && !requestHeaders.isEmpty()) {
+ Object keys[] = requestHeaders.keySet().toArray();
+ for (Object header : keys) {
+ httpDelete.setHeader(header.toString(), requestHeaders.get(header).toString());
+ }
+ }
+ response = sendReceiveRequest(httpDelete, username, password);
+ output = IOUtils.toString(response.getEntity().getContent());
+ headers = response.getAllHeaders();
+ httpStatus = response.getStatusLine().getStatusCode();
+ contentType = response.getEntity().getContentType().getValue();
+ if (log.isTraceEnabled()) {
+ log.trace("Invoked DELETE " + uri.toString() + " - Response message: " + output);
+ }
+ EntityUtils.consume(response.getEntity());
+ } finally {
+ if (response != null) {
+ IOUtils.closeQuietly(response);
+ }
+ if (httpDelete != null) {
+ httpDelete.releaseConnection();
+ }
+ }
+ return new RESTResponse(contentType, output, headers, httpStatus);
+ }
+
+ private CloseableHttpResponse sendReceiveRequest(HttpRequestBase requestBase, String username, String password)
+ throws IOException {
+ CloseableHttpResponse response;
+ if (username != null && !username.equals("") && password != null) {
+ String combinedCredentials = username + ":" + password;
+ byte[] encodedCredentials = Base64.encodeBase64(combinedCredentials.getBytes(StandardCharsets.UTF_8));
+ requestBase.addHeader("Authorization", "Basic " + new String(encodedCredentials));
+
+ response = client.execute(requestBase);
+ } else {
+ response = client.execute(requestBase);
+ }
+ return response;
+ }
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTResponse.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTResponse.java
new file mode 100644
index 0000000000..7ce0389baa
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/invoker/RESTResponse.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers.invoker;
+
+import org.apache.http.Header;
+
+/**
+ * RESTResponse class holds the data retrieved from the HTTP invoke response.
+ */
+public class RESTResponse {
+ private String contentType;
+ private String content;
+ private Header[] headers;
+ private int httpStatus;
+
+ /**
+ * Constructor
+ *
+ * @param contentType from the REST invoke response
+ * @param content from the REST invoke response
+ * @param headers from the REST invoke response
+ * @param httpStatus from the REST invoke response
+ */
+ public RESTResponse(String contentType, String content, Header[] headers, int httpStatus) {
+ this.contentType = contentType;
+ this.content = content;
+ this.headers = headers;
+ this.httpStatus = httpStatus;
+ }
+
+ /**
+ * Get the content type of the EST invoke response
+ *
+ * @return String content type of the response
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+ /**
+ * Get contents of the REST invoke response
+ *
+ * @return contents of the REST invoke response
+ */
+ public String getContent() {
+ return content;
+ }
+
+ /**
+ * Get headers of the REST invoke response
+ *
+ * @return headers of the REST invoke response
+ */
+ public Header[] getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Get the HTTP Status code from REST invoke response
+ *
+ * @return int HTTP status code
+ */
+ public int getHttpStatus() {
+ return httpStatus;
+ }
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java
new file mode 100644
index 0000000000..b7c9a00dfa
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers.utils;
+
+public class AuthConstants {
+ public static final String SEC_FAULT = "SECURITY_VALIDATION_FAILURE";
+ public static final String HTTPS = "https";
+ public static final String WSSE = "wsse";
+ public static final String SSL_CERT_X509 = "ssl.client.auth.cert.X509";
+ public static final String AUTH_CONFIGURATION_FILE_NAME = "api-filter-config.xml";
+ public static final String API_FILTER_CONFIG_ELEMENT = "apiFilterConfig";
+ public static final String API_LIST_PROPERTY = "apiList";
+ public static final String HOST = "host";
+ public static final String HTTPS_PORT = "httpsPort";
+ public static final String USERNAME = "username";
+ public static final String PASSWORD = "password";
+ public static final String MDM_SIGNATURE = "mdm-signature";
+ public static final String IOS = "ios";
+ public static final String ANDROID = "android";
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/CoreUtils.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/CoreUtils.java
new file mode 100644
index 0000000000..42a7fe9ea7
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/CoreUtils.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you 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.apimgt.handlers.utils;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.util.AXIOMUtil;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.utils.CarbonUtils;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class CoreUtils {
+ private static final Log log = LogFactory.getLog(CoreUtils.class);
+ private static String host = "localhost";
+ private static int httpsPort = 9443;
+ private static String username = "admin";
+ private static String password = "admin";
+
+ /**
+ * Reading configurations from api-filter-config.xml file
+ *
+ * @return ArrayList of api contexts
+ */
+ public static ArrayList readApiFilterList() {
+ ArrayList apiList = new ArrayList();
+ String carbonConfigDirPath = CarbonUtils.getCarbonConfigDirPath();
+ String apiFilterConfigPath = carbonConfigDirPath + File.separator +
+ AuthConstants.AUTH_CONFIGURATION_FILE_NAME;
+ File configFile = new File(apiFilterConfigPath);
+
+ try {
+ String configContent = FileUtils.readFileToString(configFile);
+ OMElement configElement = AXIOMUtil.stringToOM(configContent);
+ Iterator beans = configElement.getChildrenWithName(
+ new QName("http://www.springframework.org/schema/beans", "bean"));
+
+ while (beans.hasNext()) {
+ OMElement bean = (OMElement) beans.next();
+ String beanId = bean.getAttributeValue(new QName(null, "id"));
+ if (beanId.equals(AuthConstants.API_FILTER_CONFIG_ELEMENT)) {
+ Iterator beanProps = bean.getChildrenWithName(
+ new QName("http://www.springframework.org/schema/beans", "property"));
+
+ while (beanProps.hasNext()) {
+ OMElement beanProp = (OMElement) beanProps.next();
+ String beanName = beanProp.getAttributeValue(new QName(null, "name"));
+ if (AuthConstants.API_LIST_PROPERTY.equals(beanName)) {
+ Iterator apiListSet = ((OMElement) beanProp.getChildrenWithLocalName("set").next())
+ .getChildrenWithLocalName("value");
+ while (apiListSet.hasNext()) {
+ String apiContext = ((OMElement) apiListSet.next()).getText();
+ apiList.add(apiContext);
+ CoreUtils.debugLog(log, "Adding security to api: ", apiContext);
+ }
+ } else if (AuthConstants.HOST.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ host = value;
+ } else if (AuthConstants.HTTPS_PORT.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ if (value != null && !value.trim().equals("")) {
+ httpsPort = Integer.parseInt(value);
+ }
+ } else if (AuthConstants.USERNAME.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ username = value;
+ } else if (AuthConstants.PASSWORD.equals(beanName)) {
+ String value = beanProp.getAttributeValue(new QName(null, "value"));
+ password = value;
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ log.error("Error in reading api filter settings", e);
+ } catch (XMLStreamException e) {
+ log.error("Error in reading api filter settings", e);
+ }
+ return apiList;
+ }
+
+ /**
+ * Universal debug log function
+ *
+ * @param logger Log object specific to the class
+ * @param message initial debug log message
+ * @param vars optional strings to be appended for the log
+ */
+ public static void debugLog(Log logger, String message, Object ... vars) {
+ if(logger.isDebugEnabled()) {
+ if (vars.length < 1) {
+ logger.debug(message);
+ return;
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(message);
+ for (Object var : vars) {
+ stringBuilder.append(var.toString());
+ }
+ logger.debug(stringBuilder.toString());
+ }
+ }
+
+ public static String getHost() {
+ return host;
+ }
+
+ public static int getHttpsPort() {
+ return httpsPort;
+ }
+
+ public static String getUsername() {
+ return username;
+ }
+
+ public static String getPassword() {
+ return password;
+ }
+}
diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/resources/api-filter-config.xml b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/resources/api-filter-config.xml
new file mode 100644
index 0000000000..8811ccb8e7
--- /dev/null
+++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/resources/api-filter-config.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+ /services/echo
+ /abc
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/apimgt-extensions/pom.xml b/components/apimgt-extensions/pom.xml
index 4086cf5a18..8d486740ee 100644
--- a/components/apimgt-extensions/pom.xml
+++ b/components/apimgt-extensions/pom.xml
@@ -38,6 +38,7 @@
org.wso2.carbon.apimgt.application.extension
org.wso2.carbon.apimgt.application.extension.api
org.wso2.carbon.apimgt.annotations
+ org.wso2.carbon.apimgt.handlers
diff --git a/pom.xml b/pom.xml
index ccb5bf93d3..eeabd51d55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1930,6 +1930,10 @@
1.6.1
+
+
+ 2.1.7-wso2v7
+ 1.5.11.wso2v15