parent
fe2b6b5993
commit
d00817268e
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>apimgt-extensions</artifactId>
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<version>1.2.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>org.wso2.carbon.apimgt.handlers</artifactId>
|
||||
<name>WSO2 Carbon - API Security Handler Component</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon</groupId>
|
||||
<artifactId>org.wso2.carbon.logging</artifactId>
|
||||
<version>${carbon.kernel.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.synapse</groupId>
|
||||
<artifactId>synapse-core</artifactId>
|
||||
<version>${org.apache.synapse.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ws.security.wso2</groupId>
|
||||
<artifactId>wss4j</artifactId>
|
||||
<version>${org.apache.ws.security.wso2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||
<artifactId>org.wso2.carbon.certificate.mgt.core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json.wso2</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>${commons-json.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -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<String> 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<String, String> drcHeaders = new HashMap<String, String>();
|
||||
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<String, String> tokenHeaders = new HashMap<String, String>();
|
||||
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<String, String> certVerifyHeaders = new HashMap<String, String>();
|
||||
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);
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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<String, String> 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<String, String> 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<String, String> 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<String, String> 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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<String> readApiFilterList() {
|
||||
ArrayList<String> apiList = new ArrayList<String>();
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<bean id="restClientConfiguration">
|
||||
<property name="maxTotalConnections" value="200"/>
|
||||
<property name="maxConnectionsPerRoute" value="200"/>
|
||||
</bean>
|
||||
|
||||
<bean id="apiFilterConfig">
|
||||
<property name="apiList">
|
||||
<set>
|
||||
<value>/services/echo</value>
|
||||
<value>/abc</value>
|
||||
</set>
|
||||
</property>
|
||||
<property name="host" value="localhost"/>
|
||||
<property name="httpsPort" value="9443"/>
|
||||
<property name="username" value="admin"/>
|
||||
<property name="password" value="admin"/>
|
||||
</bean>
|
||||
</beans>
|
Loading…
Reference in new issue