diff options
Diffstat (limited to 'src/main/java/org/onap/aai/interceptors/pre')
12 files changed, 1117 insertions, 0 deletions
diff --git a/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java b/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java new file mode 100644 index 0000000..c3d9d3b --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java @@ -0,0 +1,46 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +public final class AAIRequestFilterPriority { + + private AAIRequestFilterPriority() {} + + public static final int REQUEST_TRANS_LOGGING = 1000; + + public static final int HEADER_VALIDATION = 2000; + + public static final int SET_LOGGING_CONTEXT = 3000; + + public static final int HTTP_HEADER = 4000; + + public static final int LATEST = 4250; + + public static final int AUTHORIZATION = 4500; + + public static final int RETIRED_SERVICE = 5000; + + public static final int VERSION = 5500; + + public static final int HEADER_MANIPULATION = 6000; + + public static final int REQUEST_MODIFICATION = 7000; + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java b/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java new file mode 100644 index 0000000..afacf66 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java @@ -0,0 +1,91 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.ErrorLogHelper; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.HEADER_VALIDATION) +public class HeaderValidation extends AAIContainerFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + Optional<Response> oResp; + + MultivaluedMap<String, String> headersMap = requestContext.getHeaders(); + + String transId = headersMap.getFirst(AAIHeaderProperties.TRANSACTION_ID); + String fromAppId = headersMap.getFirst(AAIHeaderProperties.FROM_APP_ID); + + List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes(); + + oResp = this.validateHeaderValuePresence(fromAppId, "AAI_4009", acceptHeaderValues); + if (oResp.isPresent()) { + requestContext.abortWith(oResp.get()); + return; + } + oResp = this.validateHeaderValuePresence(transId, "AAI_4010", acceptHeaderValues); + if (oResp.isPresent()) { + requestContext.abortWith(oResp.get()); + return; + } + + if (!this.isValidUUID(transId)) { + transId = UUID.randomUUID().toString(); + requestContext.getHeaders().get(AAIHeaderProperties.TRANSACTION_ID).clear(); + requestContext.getHeaders().add(AAIHeaderProperties.TRANSACTION_ID, transId); + } + + } + + private Optional<Response> validateHeaderValuePresence(String value, String errorCode, + List<MediaType> acceptHeaderValues) { + Response response = null; + AAIException aaie; + if (value == null) { + aaie = new AAIException(errorCode); + return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())) + .build()); + } + + return Optional.ofNullable(response); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/HttpHeaderInterceptor.java b/src/main/java/org/onap/aai/interceptors/pre/HttpHeaderInterceptor.java new file mode 100644 index 0000000..94d8ca1 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/HttpHeaderInterceptor.java @@ -0,0 +1,55 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; + +import javax.annotation.Priority; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + +/** + * The Class HttpHeaderInterceptor + */ +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.HTTP_HEADER) +public class HttpHeaderInterceptor extends AAIContainerFilter implements ContainerRequestFilter { + public static final String patchMethod = "PATCH"; + + @Override + public void filter(ContainerRequestContext containerRequestContext) throws IOException { + + MultivaluedMap<String, String> headersMap = containerRequestContext.getHeaders(); + String overrideMethod = headersMap.getFirst(AAIHeaderProperties.HTTP_METHOD_OVERRIDE); + String httpMethod = containerRequestContext.getMethod(); + + if (HttpMethod.POST.equalsIgnoreCase(httpMethod) && patchMethod.equalsIgnoreCase(overrideMethod)) { + containerRequestContext.setMethod(patchMethod); + } + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java b/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java new file mode 100644 index 0000000..6563e23 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/OneWaySslAuthorization.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.Profiles; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.service.AuthorizationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Provider +@Profile(Profiles.ONE_WAY_SSL) +@PreMatching +@Priority(AAIRequestFilterPriority.AUTHORIZATION) +public class OneWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private AuthorizationService authorizationService; + + @Override + public void filter(ContainerRequestContext containerRequestContext) throws IOException + { + + String basicAuth = containerRequestContext.getHeaderString("Authorization"); + List<MediaType> acceptHeaderValues = containerRequestContext.getAcceptableMediaTypes(); + + if(basicAuth == null || !basicAuth.startsWith("Basic ")){ + Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); + containerRequestContext.abortWith(responseOptional.get()); + return; + } + + basicAuth = basicAuth.replaceAll("Basic ", ""); + + if(!authorizationService.checkIfUserAuthorized(basicAuth)){ + Optional<Response> responseOptional = errorResponse("AAI_3300", acceptHeaderValues); + containerRequestContext.abortWith(responseOptional.get()); + return; + } + + } + + private Optional<Response> errorResponse(String errorCode, List<MediaType> acceptHeaderValues) { + AAIException aaie = new AAIException(errorCode); + return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())) + .build()); + + } +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java b/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java new file mode 100644 index 0000000..ee4807e --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RequestHeaderManipulation.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import java.util.Collections; +import java.util.regex.Matcher; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.HEADER_MANIPULATION) +public class RequestHeaderManipulation extends AAIContainerFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) { + + String uri = requestContext.getUriInfo().getPath(); + this.addRequestContext(uri, requestContext.getHeaders()); + + } + + private void addRequestContext(String uri, MultivaluedMap<String, String> requestHeaders) { + + String rc = ""; + + Matcher match = VersionInterceptor.EXTRACT_VERSION_PATTERN.matcher(uri); + if (match.find()) { + rc = match.group(1); + } + + if (requestHeaders.containsKey(AAIHeaderProperties.REQUEST_CONTEXT)) { + requestHeaders.remove(AAIHeaderProperties.REQUEST_CONTEXT); + } + requestHeaders.put(AAIHeaderProperties.REQUEST_CONTEXT, Collections.singletonList(rc)); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RequestModification.java b/src/main/java/org/onap/aai/interceptors/pre/RequestModification.java new file mode 100644 index 0000000..9c17ffc --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RequestModification.java @@ -0,0 +1,77 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.interceptors.AAIContainerFilter; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.REQUEST_MODIFICATION) +public class RequestModification extends AAIContainerFilter implements ContainerRequestFilter { + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + this.cleanDME2QueryParams(requestContext); + + } + + private void cleanDME2QueryParams(ContainerRequestContext request) { + UriBuilder builder = request.getUriInfo().getRequestUriBuilder(); + MultivaluedMap<String, String> queries = request.getUriInfo().getQueryParameters(); + + String[] blacklist = { "version", "envContext", "routeOffer" }; + Set<String> blacklistSet = Arrays.stream(blacklist).collect(Collectors.toSet()); + + boolean remove = true; + + for (String param : blacklistSet) { + if (!queries.containsKey(param)) { + remove = false; + break; + } + } + + if (remove) { + for (Map.Entry<String, List<String>> query : queries.entrySet()) { + String key = query.getKey(); + if (blacklistSet.contains(key)) { + builder.replaceQueryParam(key); + } + } + } + request.setRequestUri(builder.build()); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java b/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java new file mode 100644 index 0000000..b770296 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java @@ -0,0 +1,136 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import org.glassfish.jersey.message.internal.ReaderWriter; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.HbaseSaltPrefixer; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; +import java.util.Random; +import java.util.UUID; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.REQUEST_TRANS_LOGGING) +public class RequestTransactionLogging extends AAIContainerFilter implements ContainerRequestFilter { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RequestTransactionLogging.class); + + @Autowired + private HttpServletRequest httpServletRequest; + + private static final String DEFAULT_CONTENT_TYPE = MediaType.APPLICATION_JSON; + private static final String DEFAULT_RESPONSE_TYPE = MediaType.APPLICATION_XML; + + private static final String CONTENT_TYPE = "Content-Type"; + private static final String ACCEPT = "Accept"; + private static final String TEXT_PLAIN = "text/plain"; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String currentTimeStamp = genDate(); + String fullId = this.getAAITxIdToHeader(currentTimeStamp); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_TX_ID, fullId); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_REQUEST, this.getRequest(requestContext, fullId)); + this.addToRequestContext(requestContext, AAIHeaderProperties.AAI_REQUEST_TS, currentTimeStamp); + this.addDefaultContentType(requestContext); + } + + private void addToRequestContext(ContainerRequestContext requestContext, String name, String aaiTxIdToHeader) { + requestContext.setProperty(name, aaiTxIdToHeader); + } + + private void addDefaultContentType(ContainerRequestContext requestContext) { + + MultivaluedMap<String, String> headersMap = requestContext.getHeaders(); + String contentType = headersMap.getFirst(CONTENT_TYPE); + String acceptType = headersMap.getFirst(ACCEPT); + + if(contentType == null || contentType.contains(TEXT_PLAIN)){ + requestContext.getHeaders().putSingle(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + } + + if(acceptType == null || acceptType.contains(TEXT_PLAIN)){ + requestContext.getHeaders().putSingle(ACCEPT, DEFAULT_RESPONSE_TYPE); + } + } + + private String getAAITxIdToHeader(String currentTimeStamp) { + String txId = UUID.randomUUID().toString(); + try { + Random rand = new SecureRandom(); + int number = rand.nextInt(99999); + txId = HbaseSaltPrefixer.getInstance().prependSalt(AAIConfig.get(AAIConstants.AAI_NODENAME) + "-" + + currentTimeStamp + "-" + number ); //new Random(System.currentTimeMillis()).nextInt(99999) + } catch (AAIException e) { + } + + return txId; + } + + private String getRequest(ContainerRequestContext requestContext, String fullId) { + + JsonObject request = new JsonObject(); + request.addProperty("ID", fullId); + request.addProperty("Http-Method", requestContext.getMethod()); + request.addProperty(CONTENT_TYPE, httpServletRequest.getContentType()); + request.addProperty("Headers", requestContext.getHeaders().toString()); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream in = requestContext.getEntityStream(); + + try { + if (in.available() > 0) { + ReaderWriter.writeTo(in, out); + byte[] requestEntity = out.toByteArray(); + request.addProperty("Payload", new String(requestEntity, "UTF-8")); + requestContext.setEntityStream(new ByteArrayInputStream(requestEntity)); + } + } catch (IOException ex) { + LOGGER.error("An exception occurred during the transaction logging: " + LogFormatTools.getStackTop(ex)); + } + + return request.toString(); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/RetiredInterceptor.java b/src/main/java/org/onap/aai/interceptors/pre/RetiredInterceptor.java new file mode 100644 index 0000000..9a33b05 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/RetiredInterceptor.java @@ -0,0 +1,150 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.service.RetiredService; +import org.onap.aai.util.AAIConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +// Can cache this so if the uri was already cached then it won't run the string +// matching each time but only does it for the first time + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.RETIRED_SERVICE) +public class RetiredInterceptor extends AAIContainerFilter implements ContainerRequestFilter { + + private static final Pattern VERSION_PATTERN = Pattern.compile("v\\d+|latest"); + + private RetiredService retiredService; + + private String basePath; + + @Autowired + public RetiredInterceptor(RetiredService retiredService, @Value("${schema.uri.base.path}") String basePath){ + this.retiredService = retiredService; + this.basePath = basePath; + if(!basePath.endsWith("/")){ + this.basePath = basePath + "/"; + } + } + @Override + public void filter(ContainerRequestContext containerRequestContext) throws IOException { + + String requestURI = containerRequestContext.getUriInfo().getAbsolutePath().getPath(); + + String version = extractVersionFromPath(requestURI); + + List<Pattern> retiredAllVersionList = retiredService.getRetiredAllVersionList(); + + + if(checkIfUriRetired(containerRequestContext, retiredAllVersionList, version, requestURI, "")){ + return; + } + + List<Pattern> retiredVersionList = retiredService.getRetiredPatterns(); + + checkIfUriRetired(containerRequestContext, retiredVersionList, version, requestURI); + } + + public boolean checkIfUriRetired(ContainerRequestContext containerRequestContext, + List<Pattern> retiredPatterns, + String version, + String requestURI, + String message){ + + + for(Pattern retiredPattern : retiredPatterns){ + if(retiredPattern.matcher(requestURI).matches()){ + AAIException e; + + if(message == null){ + e = new AAIException("AAI_3007"); + } else { + e = new AAIException("AAI_3015"); + } + + ArrayList<String> templateVars = new ArrayList<>(); + + if (templateVars.isEmpty()) { + templateVars.add("PUT"); + if(requestURI != null){ + requestURI = requestURI.replaceAll(basePath, ""); + } + templateVars.add(requestURI); + if(message == null){ + templateVars.add(version); + templateVars.add(AAIConfig.get("aai.default.api.version", "")); + } + } + + Response response = Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity( + ErrorLogHelper + .getRESTAPIErrorResponse( + containerRequestContext.getAcceptableMediaTypes(), e, templateVars + ) + ) + .build(); + + containerRequestContext.abortWith(response); + + return true; + } + } + + return false; + } + + public boolean checkIfUriRetired(ContainerRequestContext containerRequestContext, + List<Pattern> retiredPatterns, + String version, + String requestURI){ + return checkIfUriRetired(containerRequestContext, retiredPatterns, version, requestURI, null); + } + + protected String extractVersionFromPath(String requestURI) { + Matcher versionMatcher = VERSION_PATTERN.matcher(requestURI); + String version = null; + + if(versionMatcher.find()){ + version = versionMatcher.group(0); + } + return version; + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java b/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java new file mode 100644 index 0000000..6c3a7fc --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java @@ -0,0 +1,75 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.LoggingContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.SET_LOGGING_CONTEXT) +public class SetLoggingContext extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private Environment environment; + + @Autowired + private HttpServletRequest httpServletRequest; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + + String uri = httpServletRequest.getRequestURI(); + String queryString = httpServletRequest.getQueryString(); + + if(queryString != null && !queryString.isEmpty()){ + uri = uri + "?" + queryString; + } + + String httpMethod = requestContext.getMethod(); + + MultivaluedMap<String, String> headersMap = requestContext.getHeaders(); + + String transId = headersMap.getFirst(AAIHeaderProperties.TRANSACTION_ID); + String fromAppId = headersMap.getFirst(AAIHeaderProperties.FROM_APP_ID); + + LoggingContext.init(); + LoggingContext.requestId(transId); + LoggingContext.partnerName(fromAppId); + LoggingContext.targetEntity(environment.getProperty("spring.application.name")); + LoggingContext.component(fromAppId); + LoggingContext.serviceName(httpMethod + " " + uri); + LoggingContext.targetServiceName(httpMethod + " " + uri); + LoggingContext.statusCode(LoggingContext.StatusCode.COMPLETE); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java b/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java new file mode 100644 index 0000000..73b7877 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java @@ -0,0 +1,187 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.auth.AAIAuthCore; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.interceptors.AAIHeaderProperties; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.restcore.HttpMethod; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; + +import javax.annotation.Priority; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.stream.Collectors; + +@Provider +@PreMatching +@Priority(AAIRequestFilterPriority.AUTHORIZATION) +@Profile("two-way-ssl") +public class TwoWaySslAuthorization extends AAIContainerFilter implements ContainerRequestFilter { + + @Autowired + private HttpServletRequest httpServletRequest; + + @Autowired + private AAIAuthCore aaiAuthCore; + + @Override + public void filter(ContainerRequestContext requestContext) { + + Optional<Response> oResp; + + String uri = requestContext.getUriInfo().getAbsolutePath().getPath(); + String httpMethod = getHttpMethod(requestContext); + + List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes(); + + Optional<String> authUser = getUser(this.httpServletRequest); + + if (authUser.isPresent()) { + oResp = this.authorize(uri, httpMethod, acceptHeaderValues, authUser.get(), + this.getHaProxyUser(this.httpServletRequest), getCertIssuer(this.httpServletRequest)); + if (oResp.isPresent()) { + requestContext.abortWith(oResp.get()); + return; + } + } else { + AAIException aaie = new AAIException("AAI_9107"); + requestContext + .abortWith(Response + .status(aaie.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper + .getRESTAPIErrorResponseWithLogging(acceptHeaderValues, aaie, new ArrayList<>())) + .build()); + } + + } + + private String getCertIssuer(HttpServletRequest hsr) { + String issuer = hsr.getHeader("X-AAI-SSL-Issuer"); + if (issuer != null && !issuer.isEmpty()) { + // the haproxy header replaces the ', ' with '/' and reverses on the '/' need to undo that. + List<String> broken = Arrays.asList(issuer.split("/")); + broken = broken.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList()); + Collections.reverse(broken); + issuer = String.join(", ", broken); + } else { + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + if (certChain != null && certChain.length > 0) { + X509Certificate clientCert = certChain[0]; + issuer = clientCert.getIssuerX500Principal().getName(); + } + } + } + return issuer; + } + + private String getHttpMethod(ContainerRequestContext requestContext) { + String httpMethod = requestContext.getMethod(); + if ("POST".equalsIgnoreCase(httpMethod) + && "PATCH".equals(requestContext.getHeaderString(AAIHeaderProperties.HTTP_METHOD_OVERRIDE))) { + httpMethod = HttpMethod.MERGE_PATCH.toString(); + } + if (httpMethod.equalsIgnoreCase(HttpMethod.MERGE_PATCH.toString()) || "patch".equalsIgnoreCase(httpMethod)) { + httpMethod = HttpMethod.PUT.toString(); + } + return httpMethod; + } + + private Optional<String> getUser(HttpServletRequest hsr) { + String authUser = null; + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + + /* + * If the certificate is null or the certificate chain length is zero Then + * retrieve the authorization in the request header Authorization Check that it + * is not null and that it starts with Basic and then strip the basic portion to + * get the base64 credentials Check if this is contained in the AAIBasicAuth + * Singleton class If it is, retrieve the username associated with that + * credentials and set to authUser Otherwise, get the principal from certificate + * and use that authUser + */ + + if (certChain == null || certChain.length == 0) { + + String authorization = hsr.getHeader("Authorization"); + + if (authorization != null && authorization.startsWith("Basic ")) { + authUser = authorization.replace("Basic ", ""); + } + + } else { + X509Certificate clientCert = certChain[0]; + X500Principal subjectDN = clientCert.getSubjectX500Principal(); + authUser = subjectDN.toString().toLowerCase(); + } + } + + return Optional.ofNullable(authUser); + } + + private String getHaProxyUser(HttpServletRequest hsr) { + String haProxyUser; + if (Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-CN")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-OU")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-O")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-L")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-ST")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-C"))) { + haProxyUser = ""; + } else { + haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s", + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-CN"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-OU"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-O"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-L"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-ST"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-C"), "")).toLowerCase(); + } + return haProxyUser; + } + + private Optional<Response> authorize(String uri, String httpMethod, List<MediaType> acceptHeaderValues, + String authUser, String haProxyUser, String issuer) { + Response response = null; + try { + if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) { + throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK"); + } + } catch (AAIException e) { + response = Response.status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(acceptHeaderValues, e, new ArrayList<>())) + .build(); + } + return Optional.ofNullable(response); + } + +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java b/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java new file mode 100644 index 0000000..f591120 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/VersionInterceptor.java @@ -0,0 +1,101 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.setup.SchemaVersion; +import org.onap.aai.setup.SchemaVersions; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Response; +import java.util.ArrayList; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@PreMatching +@Priority(AAIRequestFilterPriority.VERSION) +public class VersionInterceptor extends AAIContainerFilter implements ContainerRequestFilter { + + public static final Pattern EXTRACT_VERSION_PATTERN = Pattern.compile("^(v[1-9][0-9]*).*$"); + + private final Set<String> allowedVersions; + + private final SchemaVersions schemaVersions; + + @Autowired + public VersionInterceptor(SchemaVersions schemaVersions){ + this.schemaVersions = schemaVersions; + allowedVersions = schemaVersions.getVersions() + .stream() + .map(SchemaVersion::toString) + .collect(Collectors.toSet()); + + } + + @Override + public void filter(ContainerRequestContext requestContext) { + + String uri = requestContext.getUriInfo().getPath(); + + if (uri.startsWith("search") || uri.startsWith("util/echo") || uri.startsWith("tools")) { + return; + } + + Matcher matcher = EXTRACT_VERSION_PATTERN.matcher(uri); + + String version = null; + if(matcher.matches()){ + version = matcher.group(1); + } else { + requestContext.abortWith(createInvalidVersionResponse("AAI_3017", requestContext, version)); + return; + } + + if(!allowedVersions.contains(version)){ + requestContext.abortWith(createInvalidVersionResponse("AAI_3016", requestContext, version)); + } + } + + private Response createInvalidVersionResponse(String errorCode, ContainerRequestContext context, String version) { + AAIException e = new AAIException(errorCode); + ArrayList<String> templateVars = new ArrayList<>(); + + if (templateVars.isEmpty()) { + templateVars.add(context.getMethod()); + templateVars.add(context.getUriInfo().getPath()); + templateVars.add(version); + } + + String entity = ErrorLogHelper.getRESTAPIErrorResponse(context.getAcceptableMediaTypes(), e, templateVars); + + return Response + .status(e.getErrorObject().getHTTPResponseCode()) + .entity(entity) + .build(); + } +} diff --git a/src/main/java/org/onap/aai/interceptors/pre/VersionLatestInterceptor.java b/src/main/java/org/onap/aai/interceptors/pre/VersionLatestInterceptor.java new file mode 100644 index 0000000..61008b6 --- /dev/null +++ b/src/main/java/org/onap/aai/interceptors/pre/VersionLatestInterceptor.java @@ -0,0 +1,56 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.interceptors.pre; + +import org.onap.aai.interceptors.AAIContainerFilter; +import org.onap.aai.setup.SchemaVersions; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Priority; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import java.net.URI; + +@PreMatching +@Priority(AAIRequestFilterPriority.LATEST) +public class VersionLatestInterceptor extends AAIContainerFilter implements ContainerRequestFilter { + + private final SchemaVersions schemaVersions; + + @Autowired + public VersionLatestInterceptor(SchemaVersions schemaVersions){ + this.schemaVersions = schemaVersions; + } + + @Override + public void filter(ContainerRequestContext requestContext) { + + String uri = requestContext.getUriInfo().getPath(); + + if(uri.startsWith("latest")){ + String absolutePath = requestContext.getUriInfo().getAbsolutePath().toString(); + String latest = absolutePath.replaceFirst("latest", schemaVersions.getDefaultVersion().toString()); + requestContext.setRequestUri(URI.create(latest)); + return; + } + + } +} |