Skip to content

Commit

Permalink
add request in and out interceptors for recording history.
Browse files Browse the repository at this point in the history
  • Loading branch information
dushaniw committed Jan 18, 2021
1 parent 6b66a17 commit f0e313c
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package org.wso2.carbon.apimgt.rest.api.common;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

public final class RestApiConstants {
Expand Down Expand Up @@ -303,4 +306,11 @@ public final class RestApiConstants {

public static final String AUTHENTICATION_ADMIN_SERVICE_ENDPOINT = "AuthenticationAdmin";

//API History related constants
public static final String LOGGED_IN_USERNAME = "loggedInUser";
public static final String PARAM_API_ID = "apiId";
public static final String HISTORY_EVENT = "historyEvent";
public static final List<String> DTO_CLASSES_TO_RECORD_HISTORY = new ArrayList<>(
Arrays.asList("APIDTO", "DocumentDTO", "GraphQLQueryComplexityInfoDTO", "APIProductDTO",
"APIMonetizationInfoDTO", "ResourcePolicyInfoDTO"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<bean id="URLValidationInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.URLValidationInterceptor" />
<bean id="PreAuthenticationInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.PreAuthenticationInterceptor" />
<bean id="TokenMergeInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.auth.TokenMergeInterceptor" />
<bean id="LogRequestInInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.request.LogRequestInInterceptor"/>
<bean id="RequestInHistoryInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.request.RequestInHistoryInterceptor"/>

<!-- For Basic Authentication scheme please comment the AuthenticationInterceptor which contains "OAuthAuthenticationInterceptor"
and uncomment the AuthenticationInterceptor which contains "BasicAuthenticationInterceptor"-->
Expand All @@ -77,7 +77,7 @@
<!-- Out interceptors -->
<bean id="gZipInterceptor" class="org.apache.cxf.transport.common.gzip.GZIPOutInterceptor" />
<bean id="responseInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.response.ResponseOutInterceptor" />
<bean id="LogResponseOutInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.response.LogResponseOutInterceptor"/>
<bean id="ResponseOutHistoryInterceptor" class="org.wso2.carbon.apimgt.rest.api.util.interceptors.response.ResponseOutHistoryInterceptor"/>

<cxf:bus>
<cxf:inInterceptors>
Expand All @@ -87,11 +87,11 @@
<ref bean="AuthenticationInterceptor"/>
<ref bean="BasicAuthenticationInterceptor"/>
<ref bean="PostAuthenticationInterceptor"/>
<ref bean="RequestInHistoryInterceptor"/>
<ref bean="ValidationInInterceptor"/>
<ref bean="LogRequestInInterceptor"/>
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="LogResponseOutInterceptor"/>
<ref bean="ResponseOutHistoryInterceptor"/>
<ref bean="gZipInterceptor"/>
<ref bean="responseInterceptor"/>
</cxf:outInterceptors>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* Copyright (c) 2021 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.rest.api.util.interceptors.request;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.impl.UriInfoImpl;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.Parameter;
import org.apache.cxf.jaxrs.model.ParameterType;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.wso2.carbon.apimgt.api.model.HistoryEvent;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.rest.api.common.RestApiConstants;

import java.sql.Timestamp;
import java.util.List;

import javax.ws.rs.core.UriInfo;

public class RequestInHistoryInterceptor extends AbstractPhaseInterceptor {

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

public RequestInHistoryInterceptor() {

super(Phase.PRE_INVOKE);
}

@Override
public void handleMessage(Message message) throws Fault {

String basePath = (String) message.get(Message.BASE_PATH);
String resourcePath = ((String) message.get(Message.REQUEST_URI)).substring(basePath.length() - 1);
String verb = (String) message.get(Message.HTTP_REQUEST_METHOD);
boolean recordHistory = message.getExchange().get(APIConstants.SWAGGER_X_RECORD_HISTORY) != null &&
(boolean) message.getExchange().get(APIConstants.SWAGGER_X_RECORD_HISTORY);
boolean recordPayload = message.getExchange().get(APIConstants.SWAGGER_X_RECORD_HISTORY_PAYLOAD) != null &&
(boolean) message.getExchange().get(APIConstants.SWAGGER_X_RECORD_HISTORY_PAYLOAD);
String operationId = (String) message.getExchange().get(APIConstants.SWAGGER_OPERATION_ID);
String loggedInUser = (String) message.getExchange().get(RestApiConstants.LOGGED_IN_USERNAME);

if (recordHistory) {
UriInfo uriInfo = new UriInfoImpl(message);
MetadataMap<String, String> metadataMap = (MetadataMap<String, String>) uriInfo.getPathParameters();
String apiId = metadataMap.getFirst(RestApiConstants.PARAM_API_ID);
String queryParamString = StringUtils.EMPTY;

MetadataMap<String, String> queryDataMap = (MetadataMap<String, String>) uriInfo.getQueryParameters();
List<Parameter> parameterList =
message.getExchange().get(OperationResourceInfo.class).getParameters();
if (queryDataMap != null && !queryDataMap.isEmpty() && parameterList != null
&& !parameterList.isEmpty()) {
StringBuilder queryParamBuilder = new StringBuilder();
boolean isFirst = true;
for (Parameter param : parameterList) {
if (param.getType() == ParameterType.QUERY) {
String paramName = param.getName();
if (queryDataMap.containsKey(paramName)) {
if (isFirst) {
queryParamBuilder.append("?");
isFirst = false;
} else {
queryParamBuilder.append("&");
}
queryParamBuilder.append(paramName).append("=").append(queryDataMap.get(paramName));
}
}
}
queryParamString = queryParamBuilder.toString();
}

//Create a HistoryEvent object and assign values
HistoryEvent historyEvent = new HistoryEvent();
historyEvent.setApiId(apiId);
historyEvent.setUser(loggedInUser);
historyEvent.setDescription(verb + StringUtils.SPACE + resourcePath + queryParamString);
historyEvent.setOperationId(operationId);
historyEvent.setCreatedTime(new Timestamp(System.currentTimeMillis()));
if (recordPayload) {
if (log.isDebugEnabled()) {
log.debug("Recording payload for: " + StringUtils.SPACE
+ verb + StringUtils.SPACE + resourcePath);
}
MessageContentsList messageContentsList = MessageContentsList.getContentsList(message);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
StringBuilder payloadBuilder = new StringBuilder();
for (Object messageContent : messageContentsList) {
if (messageContent != null) {
String messageContentObjType = messageContent.getClass().getSimpleName();
if (RestApiConstants.DTO_CLASSES_TO_RECORD_HISTORY.contains(messageContentObjType)) {
payloadBuilder.append(gson.toJson(messageContent));
}
}
}
String payload = payloadBuilder.toString();
payload.replaceAll("\"password\": \".*\"", "\"password\": \"*****\"")
.replaceAll("\"clientSecret\": \".*\"", "\"clientSecret\": \"*****\"")
.replaceAll("\"amznAccessKey\": \".*\"", "\"amznAccessKey\": \"*****\"")
.replaceAll("\"amznSecretKey\": \".*\"", "\"amznSecretKey\": \"*****\"");
historyEvent.setPayload(payload.getBytes());
}
message.getExchange().put(RestApiConstants.HISTORY_EVENT, historyEvent);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2021 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.rest.api.util.interceptors.response;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.model.HistoryEvent;
import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO;
import org.wso2.carbon.apimgt.rest.api.common.RestApiConstants;
import org.wso2.carbon.apimgt.rest.api.util.interceptors.request.RequestInHistoryInterceptor;

public class ResponseOutHistoryInterceptor extends AbstractPhaseInterceptor {

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

public ResponseOutHistoryInterceptor() {

super(Phase.SEND);
}

@Override
public void handleMessage(Message message) throws Fault {

if (message.get(Message.RESPONSE_CODE) != null
&& ((Integer) message.get(Message.RESPONSE_CODE) == 200
|| (Integer) message.get(Message.RESPONSE_CODE) == 201)) {
HistoryEvent historyEvent = (HistoryEvent) message.getExchange().get(RestApiConstants.HISTORY_EVENT);
if (historyEvent != null) {
try {

if (historyEvent.getApiId() == null) {
String apiId = (String) message.getExchange().getInMessage().get(RestApiConstants.PARAM_API_ID);
if (StringUtils.isNotBlank(apiId)) {
historyEvent.setApiId(apiId);
} else {
log.error("API Id not found to record history event for :" + historyEvent.getOperationId()
+ StringUtils.SPACE + historyEvent.getDescription());
return;
}
}
// String revisionKey =
// (String) message.getExchange().getInMessage().get(RestApiConstants.PARAM_REVISION_KEY);
// if (StringUtils.isNotBlank(revisionKey)) {
// historyEvent.setRevisionKey(revisionKey);
// }
ApiMgtDAO.getInstance().addHistoryEvent(historyEvent);
} catch (APIManagementException e) {
log.error("Error while recoding history event for: " + historyEvent.getOperationId()
+ StringUtils.SPACE + historyEvent.getDescription());
}
}
}
}
}

0 comments on commit f0e313c

Please sign in to comment.