Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unknown query parameter and X-forwarded-host header control. #610

Merged
merged 1 commit into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -47,8 +50,6 @@
public class WebMVCConfig implements WebMvcConfigurer {
private static final Logger log = LoggerFactory.getLogger(WebMVCConfig.class);



@Value("${server.contextPath}")
private String contextPath;

Expand Down Expand Up @@ -179,4 +180,12 @@ static public Class<? extends ProductBusinessLogic> selectFormatterClass(String

}

@Autowired
private SecurityValidationFilter queryParameterValidationInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(queryParameterValidationInterceptor);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -150,7 +154,6 @@ private ResponseEntity<Object> 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<Object> selectByLidvid(String identifier, List<String> fields)
throws UnhandledException, NotFoundException, AcceptFormatNotSupportedException {
Expand Down Expand Up @@ -226,6 +229,7 @@ public ResponseEntity<Object> selectByLidvidAll(String identifier, List<String>
public ResponseEntity<Object> productList(List<String> fields, List<String> keywords,
Integer limit, String q, List<String> sort, List<String> searchAfter) throws Exception {


SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext)
.applyMultipleProductsDefaults(fields, q, keywords, limit, sort, searchAfter, true).build();

Expand Down Expand Up @@ -648,23 +652,27 @@ public ResponseEntity<List<PropertiesListInner>> productPropertiesList() throws
Set<String> resultIndexNames = getMappingResponse.result().keySet();
SortedMap<String, PropertiesListInner.TypeEnum> aggregatedMappings = new TreeMap<>();
for (String indexName : resultIndexNames) {
Set<Map.Entry<String, Property>> indexProperties = getMappingResponse.result().get(indexName).mappings().properties().entrySet();
Set<Map.Entry<String, Property>> indexProperties =
getMappingResponse.result().get(indexName).mappings().properties().entrySet();
for (Map.Entry<String, Property> 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<PropertiesListInner> apiResponseContent = aggregatedMappings.entrySet().stream().map((entry) -> {
PropertiesListInner propertyElement = new PropertiesListInner();
propertyElement.setProperty(entry.getKey());
propertyElement.setType(entry.getValue());
return propertyElement;
}).toList();
List<PropertiesListInner> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,17 @@ protected ResponseEntity<Object> unparsableQParam(UnparsableQParamException ex,
return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(value = {UnknownQueryParameterException.class})
public ResponseEntity<Object> unknownQueryParameter(UnknownQueryParameterException ex,
WebRequest request) {
return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(value = {UnauthorizedForwardedHostException.class})
public ResponseEntity<Object> unknownQueryParameter(UnauthorizedForwardedHostException ex,
WebRequest request) {
return genericExceptionHandler(ex, request, "", HttpStatus.BAD_REQUEST);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@
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;
import gov.nasa.pds.model.Summary;


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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
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;
import org.springframework.web.context.request.ServletRequestAttributes;
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
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@
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;
import gov.nasa.pds.model.WyriwygProductKeyValuePair;
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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions service/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading