diff --git a/service/src/main/java/gov/nasa/pds/api/registry/configuration/WebMVCConfig.java b/service/src/main/java/gov/nasa/pds/api/registry/configuration/WebMVCConfig.java index 5a7202fe..69dddc45 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/configuration/WebMVCConfig.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/configuration/WebMVCConfig.java @@ -6,6 +6,7 @@ import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -15,6 +16,7 @@ import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -39,6 +41,7 @@ import gov.nasa.pds.api.registry.view.PdsProductXMLSerializer; import gov.nasa.pds.api.registry.view.PdsProductsXMLSerializer; import gov.nasa.pds.api.registry.view.XmlErrorMessageSerializer; +import gov.nasa.pds.api.registry.controllers.SecurityValidationFilter; @Configuration @EnableWebMvc @@ -47,8 +50,6 @@ public class WebMVCConfig implements WebMvcConfigurer { private static final Logger log = LoggerFactory.getLogger(WebMVCConfig.class); - - @Value("${server.contextPath}") private String contextPath; @@ -179,4 +180,12 @@ static public Class selectFormatterClass(String } + @Autowired + private SecurityValidationFilter queryParameterValidationInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(queryParameterValidationInterceptor); + } + } diff --git a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java index 1a040f7f..dccd3a2c 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java @@ -12,6 +12,9 @@ import gov.nasa.pds.api.registry.model.identifiers.PdsLidVid; import gov.nasa.pds.api.registry.model.identifiers.PdsProductClasses; import gov.nasa.pds.api.registry.model.properties.PdsProperty; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import com.fasterxml.jackson.databind.ObjectMapper; import org.opensearch.client.opensearch.OpenSearchClient; @@ -48,8 +51,9 @@ @Controller -// TODO: Refactor common controller code out of ProductsController and split the additional API implementations out into -// corresponding controllers +// TODO: Refactor common controller code out of ProductsController and split the additional API +// implementations out into +// corresponding controllers public class ProductsController implements ProductsApi, ClassesApi, PropertiesApi { @Override @@ -150,7 +154,6 @@ private ResponseEntity formatMultipleProducts(RawMultipleProductResponse // lid, suffix latest, we want the latest lidvid which lid matches (case latest) // lid suffix all, we want all the lidvid which lid matches (case all) // lidvid, suffix all, we want the exact match with the lidvid (case exact) - @Override public ResponseEntity selectByLidvid(String identifier, List fields) throws UnhandledException, NotFoundException, AcceptFormatNotSupportedException { @@ -226,6 +229,7 @@ public ResponseEntity selectByLidvidAll(String identifier, List public ResponseEntity productList(List fields, List keywords, Integer limit, String q, List sort, List searchAfter) throws Exception { + SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) .applyMultipleProductsDefaults(fields, q, keywords, limit, sort, searchAfter, true).build(); @@ -648,23 +652,27 @@ public ResponseEntity> productPropertiesList() throws Set resultIndexNames = getMappingResponse.result().keySet(); SortedMap aggregatedMappings = new TreeMap<>(); for (String indexName : resultIndexNames) { - Set> indexProperties = getMappingResponse.result().get(indexName).mappings().properties().entrySet(); + Set> indexProperties = + getMappingResponse.result().get(indexName).mappings().properties().entrySet(); for (Map.Entry property : indexProperties) { String jsonPropertyName = PdsProperty.toJsonPropertyString(property.getKey()); Property openPropertyName = property.getValue(); - PropertiesListInner.TypeEnum propertyEnumType = _resolvePropertyToEnumType(openPropertyName); + PropertiesListInner.TypeEnum propertyEnumType = + _resolvePropertyToEnumType(openPropertyName); -// No consistency-checking between duplicates, for now. TODO: add error log for mismatching duplicates + // No consistency-checking between duplicates, for now. TODO: add error log for mismatching + // duplicates aggregatedMappings.put(jsonPropertyName, propertyEnumType); } } - List apiResponseContent = aggregatedMappings.entrySet().stream().map((entry) -> { - PropertiesListInner propertyElement = new PropertiesListInner(); - propertyElement.setProperty(entry.getKey()); - propertyElement.setType(entry.getValue()); - return propertyElement; - }).toList(); + List apiResponseContent = + aggregatedMappings.entrySet().stream().map((entry) -> { + PropertiesListInner propertyElement = new PropertiesListInner(); + propertyElement.setProperty(entry.getKey()); + propertyElement.setType(entry.getValue()); + return propertyElement; + }).toList(); return new ResponseEntity<>(apiResponseContent, HttpStatus.OK); } diff --git a/service/src/main/java/gov/nasa/pds/api/registry/controllers/RegistryApiResponseEntityExceptionHandler.java b/service/src/main/java/gov/nasa/pds/api/registry/controllers/RegistryApiResponseEntityExceptionHandler.java index baec35d7..74a0093e 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/controllers/RegistryApiResponseEntityExceptionHandler.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/controllers/RegistryApiResponseEntityExceptionHandler.java @@ -79,5 +79,17 @@ protected ResponseEntity unparsableQParam(UnparsableQParamException ex, return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST); } + @ExceptionHandler(value = {UnknownQueryParameterException.class}) + public ResponseEntity unknownQueryParameter(UnknownQueryParameterException ex, + WebRequest request) { + return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(value = {UnauthorizedForwardedHostException.class}) + public ResponseEntity unknownQueryParameter(UnauthorizedForwardedHostException ex, + WebRequest request) { + return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST); + } + } diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/Pds4ProductBusinessObject.java b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/Pds4ProductBusinessObject.java index fb30a4df..84ba0dff 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/Pds4ProductBusinessObject.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/Pds4ProductBusinessObject.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; import gov.nasa.pds.api.registry.model.Pds4ProductFactory; +import gov.nasa.pds.api.registry.model.exceptions.UnauthorizedForwardedHostException; import gov.nasa.pds.api.registry.search.HitIterator; import gov.nasa.pds.model.Pds4Product; import gov.nasa.pds.model.Pds4Products; @@ -30,7 +31,7 @@ public class Pds4ProductBusinessObject extends ProductBusinessLogicImpl { public final boolean isJSON; public final String[] PDS4_PRODUCT_FIELDS; - public Pds4ProductBusinessObject(boolean isJSON) { + public Pds4ProductBusinessObject(boolean isJSON) throws UnauthorizedForwardedHostException { super(); String temp[] = { // BLOB diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/PdsProductBusinessObject.java b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/PdsProductBusinessObject.java index 8845d73d..8714710d 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/PdsProductBusinessObject.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/PdsProductBusinessObject.java @@ -13,6 +13,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import gov.nasa.pds.api.registry.model.EntityProduct; import gov.nasa.pds.api.registry.model.SearchUtil; +import gov.nasa.pds.api.registry.model.exceptions.UnauthorizedForwardedHostException; import gov.nasa.pds.api.registry.search.HitIterator; import gov.nasa.pds.model.PdsProduct; import gov.nasa.pds.model.PdsProducts; @@ -20,11 +21,16 @@ public class PdsProductBusinessObject extends ProductBusinessLogicImpl { + private static final Logger log = LoggerFactory.getLogger(PdsProductBusinessObject.class); private ObjectMapper objectMapper; private PdsProduct product = null; private PdsProducts products = null; + public PdsProductBusinessObject() throws UnauthorizedForwardedHostException { + super(); + // TODO Auto-generated constructor stub + } @Override public String[] getMaximallyRequiredFields() { diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/ProductBusinessLogicImpl.java b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/ProductBusinessLogicImpl.java index 00792a66..86d49909 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/ProductBusinessLogicImpl.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/ProductBusinessLogicImpl.java @@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; import org.springframework.web.context.request.RequestContextHolder; @@ -17,6 +18,7 @@ import gov.nasa.pds.api.registry.exceptions.UnsupportedSearchProperty; import gov.nasa.pds.api.registry.model.BlobUtil; import gov.nasa.pds.api.registry.model.SearchUtil; +import gov.nasa.pds.api.registry.model.exceptions.UnauthorizedForwardedHostException; @Component @RequestScope @@ -48,9 +50,12 @@ public ProductBusinessLogicImpl() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + String proxyContextPath = request.getContextPath(); ProductBusinessLogicImpl.log.debug("contextPath is: '" + proxyContextPath + "'"); + String serverName = request.getServerName(); + if (ProductBusinessLogicImpl.proxyRunsOnDefaultPort(request)) { this.baseURL = new URL(request.getScheme(), request.getServerName(), proxyContextPath); } else { diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/WyriwygBusinessObject.java b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/WyriwygBusinessObject.java index bf0e5a85..050db29b 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/WyriwygBusinessObject.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/api_responses/WyriwygBusinessObject.java @@ -14,6 +14,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import gov.nasa.pds.api.registry.exceptions.UnsupportedSearchProperty; import gov.nasa.pds.api.registry.model.SearchUtil; +import gov.nasa.pds.api.registry.model.exceptions.UnauthorizedForwardedHostException; import gov.nasa.pds.api.registry.search.HitIterator; import gov.nasa.pds.model.Summary; import gov.nasa.pds.model.WyriwygProduct; @@ -21,6 +22,13 @@ import gov.nasa.pds.model.WyriwygProducts; public class WyriwygBusinessObject extends ProductBusinessLogicImpl { + + public WyriwygBusinessObject() throws UnauthorizedForwardedHostException { + super(); + // TODO Auto-generated constructor stub + } + + private static final Logger log = LoggerFactory.getLogger(WyriwygBusinessObject.class); @SuppressWarnings("unused") diff --git a/service/src/main/java/gov/nasa/pds/api/registry/model/exceptions/RegistryApiException.java b/service/src/main/java/gov/nasa/pds/api/registry/model/exceptions/RegistryApiException.java index 3873560e..fa6d10a9 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/model/exceptions/RegistryApiException.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/model/exceptions/RegistryApiException.java @@ -3,10 +3,12 @@ import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jakarta.servlet.ServletException; -public class RegistryApiException extends Exception { - private static final long serialVersionUID = 202822323640754980L; + +public class RegistryApiException extends ServletException { + private static final long serialVersionUID = 2533946352056320649L; private static final Logger log = LoggerFactory.getLogger(RegistryApiException.class); diff --git a/service/src/main/resources/application.properties b/service/src/main/resources/application.properties index 2cadcf58..bd25cc75 100644 --- a/service/src/main/resources/application.properties +++ b/service/src/main/resources/application.properties @@ -13,6 +13,7 @@ springdoc.api-docs.enabled=true springdoc.packagesToScan=gov.nasa.pds.api.registry.controllers springdoc.pathsToMatch=/** server.forward-headers-strategy=framework +server.authorizedForwardedHost=localhost management.endpoints.web.exposure.include=* spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false