aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Arrastia <MArrasti@amdocs.com>2018-06-08 10:40:54 +0100
committerMichael Arrastia <MArrasti@amdocs.com>2018-06-08 10:40:54 +0100
commitfcf9451685f6de438a66b84189eba3a9b0db73a1 (patch)
tree92ca1992f6a4f1023cb3eeb7713e4b1731510307
parent7eb81d52479e247050bee5968b2702030bf2c8c4 (diff)
Add validation of request headers
Enforces presence of X-FromAppId and X-TransactionId headers in REST requests. Change-Id: I539e863049e4d5a985d9e952ee7dcbf3fd97f7b3 Issue-ID: AAI-1194 Signed-off-by: Michael Arrastia <MArrasti@amdocs.com>
-rw-r--r--champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java42
-rw-r--r--champ-service/src/main/java/org/onap/champ/util/HttpHeadersValidator.java48
-rw-r--r--champ-service/src/test/java/org/onap/champ/util/MockHeaders.java100
-rw-r--r--champ-service/src/test/java/org/onap/champ/util/TestHttpHeadersValidator.java75
4 files changed, 255 insertions, 10 deletions
diff --git a/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java
index 726944b..b312af3 100644
--- a/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java
+++ b/champ-service/src/main/java/org/onap/champ/ChampRESTAPI.java
@@ -69,6 +69,7 @@ import org.onap.champ.service.logging.ChampMsgs;
import org.onap.champ.service.logging.LoggingUtil;
import org.onap.champ.util.ChampProperties;
import org.onap.champ.util.ChampServiceConstants;
+import org.onap.champ.util.HttpHeadersValidator;
import org.onap.champ.util.etag.EtagGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -81,6 +82,7 @@ public class ChampRESTAPI {
private ChampDataService champDataService;
private EtagGenerator etagGenerator;
+ private HttpHeadersValidator httpHeadersValidator;
private String TRANSACTION_METHOD = "method";
private Timer timer;
@@ -108,6 +110,7 @@ public class ChampRESTAPI {
mapper.registerModule(module);
etagGenerator = new EtagGenerator();
+ httpHeadersValidator = new HttpHeadersValidator();
}
@GET
@@ -130,6 +133,7 @@ public class ChampRESTAPI {
ChampObject retrieved;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
@@ -168,6 +172,7 @@ public class ChampRESTAPI {
logger.info(ChampMsgs.INCOMING_REQUEST, tId, objectId);
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
@@ -201,6 +206,7 @@ public class ChampRESTAPI {
logger.info(ChampMsgs.INCOMING_REQUEST, tId, champObj);
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
@@ -240,6 +246,7 @@ public class ChampRESTAPI {
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
@@ -277,6 +284,7 @@ public class ChampRESTAPI {
Response response = null;
ChampTransaction transaction = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
retrieved = champDataService.getRelationshipsByObject(oId, Optional.ofNullable(transaction));
EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(retrieved));
response = Response.status(Status.OK).entity(mapper.writeValueAsString(retrieved)).tag(eTag).build();
@@ -320,12 +328,12 @@ public class ChampRESTAPI {
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
champObjects = champDataService.queryObjects(filter, properties);
EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampObjects(champObjects));
response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champObjects))
.build();
} catch (JsonProcessingException e) {
- e.printStackTrace();
response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (ChampServiceException e1) {
response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
@@ -350,6 +358,7 @@ public class ChampRESTAPI {
ChampRelationship retrieved;
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
@@ -388,6 +397,7 @@ public class ChampRESTAPI {
logger.info(ChampMsgs.INCOMING_REQUEST, tId, relationship);
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
@@ -427,6 +437,7 @@ public class ChampRESTAPI {
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
@@ -462,6 +473,7 @@ public class ChampRESTAPI {
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
ChampTransaction transaction = champDataService.getTransaction(tId);
if (tId != null && transaction == null) {
throw new ChampServiceException("transactionId not found", Status.BAD_REQUEST);
@@ -499,12 +511,12 @@ public class ChampRESTAPI {
}
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
champRelationshipList = champDataService.queryRelationships(filter);
EntityTag eTag = new EntityTag(etagGenerator.computeHashForChampRelationships(champRelationshipList));
response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).tag(eTag).entity(mapper.writeValueAsString(champRelationshipList))
.build();
} catch (JsonProcessingException e) {
- e.printStackTrace();
response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (ChampServiceException e1) {
response = Response.status(e1.getHttpStatus()).entity(e1.getMessage()).build();
@@ -525,14 +537,19 @@ public class ChampRESTAPI {
@Context HttpServletRequest req) {
LoggingUtil.initMdcContext(req, headers);
long startTimeInMs = System.currentTimeMillis();
- Status s;
- String transaction = champDataService.openTransaction();
-
- s = Status.OK;
- Response response = Response.status(s).entity(transaction).build();
- logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString());
- LoggingUtil.logRestRequest(logger, auditLogger, req, response);
- metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs));
+ Response response = null;
+ try {
+ httpHeadersValidator.validateRequestHeaders(headers);
+ String transaction = champDataService.openTransaction();
+ Status s = Status.OK;
+ response = Response.status(s).entity(transaction).build();
+ logger.info(ChampMsgs.PROCESS_EVENT, "Opened Transaction with ID: " + transaction, s.toString());
+ } catch (ChampServiceException e) {
+ response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
+ } finally {
+ LoggingUtil.logRestRequest(logger, auditLogger, req, response);
+ metricsLogger.info(ChampMsgs.PROCESSED_REQUEST, "POST", Long.toString(System.currentTimeMillis() - startTimeInMs));
+ }
return response;
}
@@ -551,9 +568,12 @@ public class ChampRESTAPI {
}
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
response = Response.status(Status.OK).entity(mapper.writeValueAsString(tId + " is OPEN")).build();
} catch (JsonProcessingException e) {
response = Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ } catch (ChampServiceException e) {
+ response = Response.status(e.getHttpStatus()).entity(e.getMessage()).build();
} catch (Exception e) {
response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
LoggingUtil.logInternalError(logger, e);
@@ -576,6 +596,7 @@ public class ChampRESTAPI {
Response response = null;
try {
+ httpHeadersValidator.validateRequestHeaders(headers);
JSONObject jsonObj = new JSONObject(t);
String method = jsonObj.getString(this.TRANSACTION_METHOD);
@@ -606,6 +627,7 @@ public class ChampRESTAPI {
}
return response;
}
+
private boolean reservedKeyMatcher(Pattern p, String key) {
Matcher m = p.matcher ( key );
if (m.matches()) {
diff --git a/champ-service/src/main/java/org/onap/champ/util/HttpHeadersValidator.java b/champ-service/src/main/java/org/onap/champ/util/HttpHeadersValidator.java
new file mode 100644
index 0000000..df85997
--- /dev/null
+++ b/champ-service/src/main/java/org/onap/champ/util/HttpHeadersValidator.java
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 Amdocs
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ */
+package org.onap.champ.util;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response.Status;
+import org.onap.champ.exception.ChampServiceException;
+
+public class HttpHeadersValidator {
+
+ public void validateRequestHeaders(HttpHeaders headers) throws ChampServiceException {
+ String sourceOfTruth = null;
+ if (headers.getRequestHeaders().containsKey("X-FromAppId")) {
+ sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId");
+ }
+
+ if (sourceOfTruth == null || sourceOfTruth.trim() == "") {
+ throw new ChampServiceException("Invalid request, Missing X-FromAppId header", Status.BAD_REQUEST);
+ }
+
+ String transId = null;
+ if (headers.getRequestHeaders().containsKey("X-TransactionId")) {
+ transId = headers.getRequestHeaders().getFirst("X-TransactionId");
+ }
+
+ if (transId == null || transId.trim() == "") {
+ throw new ChampServiceException("Invalid request, Missing X-TransactionId header", Status.BAD_REQUEST);
+ }
+ }
+}
diff --git a/champ-service/src/test/java/org/onap/champ/util/MockHeaders.java b/champ-service/src/test/java/org/onap/champ/util/MockHeaders.java
new file mode 100644
index 0000000..1b248fb
--- /dev/null
+++ b/champ-service/src/test/java/org/onap/champ/util/MockHeaders.java
@@ -0,0 +1,100 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 Amdocs
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ */
+package org.onap.champ.util;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+public class MockHeaders implements HttpHeaders {
+
+ private MultivaluedMap<String, String> headers;
+
+ public MockHeaders() {
+ headers = new MultivaluedHashMap<String, String>();
+ headers.add("X-FromAppId", "test-app");
+ headers.add("X-TransactionId", "65f7e29c-57fd-45b2-bfd5-19e25c59110e");
+ }
+
+ @Override
+ public List<Locale> getAcceptableLanguages() {
+ return null;
+ }
+
+ @Override
+ public List<MediaType> getAcceptableMediaTypes() {
+ return null;
+ }
+
+ @Override
+ public Map<String, Cookie> getCookies() {
+ return null;
+ }
+
+ @Override
+ public Date getDate() {
+ return null;
+ }
+
+ @Override
+ public String getHeaderString(String arg0) {
+ return null;
+ }
+
+ @Override
+ public Locale getLanguage() {
+ return null;
+ }
+
+ @Override
+ public int getLength() {
+ return 0;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<String> getRequestHeader(String arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public MultivaluedMap<String, String> getRequestHeaders() {
+ return headers;
+ }
+
+ public void clearRequestHeader(String... keys) {
+ for (String key : keys) {
+ headers.remove(key);
+ }
+ }
+}
diff --git a/champ-service/src/test/java/org/onap/champ/util/TestHttpHeadersValidator.java b/champ-service/src/test/java/org/onap/champ/util/TestHttpHeadersValidator.java
new file mode 100644
index 0000000..aa00dc1
--- /dev/null
+++ b/champ-service/src/test/java/org/onap/champ/util/TestHttpHeadersValidator.java
@@ -0,0 +1,75 @@
+/**
+ * ============LICENSE_START==========================================
+ * org.onap.aai
+ * ===================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 Amdocs
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ */
+package org.onap.champ.util;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onap.champ.exception.ChampServiceException;
+
+public class TestHttpHeadersValidator {
+
+ private static HttpHeadersValidator champRestApi;
+
+ @BeforeClass
+ public static void setupBeforeClass() throws Exception {
+ champRestApi = new HttpHeadersValidator();
+ }
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testValidRequestHeader() throws ChampServiceException {
+ champRestApi.validateRequestHeaders(new MockHeaders());
+ }
+
+ @Test
+ public void testInvalidRequestHeaderXTransactionId() throws ChampServiceException {
+ thrown.expect(ChampServiceException.class);
+ thrown.expectMessage("Invalid request, Missing X-TransactionId header");
+
+ MockHeaders MockHeaders = new MockHeaders();
+ MockHeaders.clearRequestHeader("X-TransactionId");
+ champRestApi.validateRequestHeaders(MockHeaders);
+ }
+
+ @Test
+ public void testInvalidRequestHeaderXFromAppId() throws ChampServiceException {
+ thrown.expect(ChampServiceException.class);
+ thrown.expectMessage("Invalid request, Missing X-FromAppId header");
+
+ MockHeaders MockHeaders = new MockHeaders();
+ MockHeaders.clearRequestHeader("X-FromAppId");
+ champRestApi.validateRequestHeaders(MockHeaders);
+ }
+
+ @Test
+ public void testEmptyRequestHeader() throws ChampServiceException {
+ thrown.expect(ChampServiceException.class);
+ thrown.expectMessage("Invalid request, Missing X-FromAppId header");
+
+ MockHeaders MockHeaders = new MockHeaders();
+ MockHeaders.clearRequestHeader("X-TransactionId", "X-FromAppId");
+ champRestApi.validateRequestHeaders(MockHeaders);
+ }
+}