NIFI-13606 Corrected Custom UI loading in reverse proxy deployments

This closes #9130

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
Matt Gilman 2024-07-31 10:10:04 -04:00 committed by exceptionfactory
parent 2542927b53
commit 6c930626dc
No known key found for this signature in database
6 changed files with 52 additions and 21 deletions

View File

@ -154,6 +154,21 @@ public abstract class ApplicationResource {
return buildResourceUri(uriBuilder.replacePath(ROOT_PATH).build());
}
/**
* Generate a URI to an external UI.
*
* @param pathSegments path segments for the external UI
* @return the full external UI
*/
protected String generateExternalUiUri(final String... pathSegments) {
final RequestUriBuilder builder = RequestUriBuilder.fromHttpServletRequest(httpServletRequest, properties.getAllowedContextPathsAsList());
final String path = String.join("/", pathSegments);
builder.path(path);
return builder.build().toString();
}
private URI buildResourceUri(final String... path) {
final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
return buildResourceUri(uriBuilder.segment(path).build());

View File

@ -156,7 +156,7 @@ public class ControllerServiceResource extends ApplicationResource {
final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(controllerService.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion());
for (final UiExtension uiExtension : uiExtensions) {
if (UiExtensionType.ControllerServiceConfiguration.equals(uiExtension.getExtensionType())) {
controllerService.setCustomUiUrl(uiExtension.getContextPath() + "/configure");
controllerService.setCustomUiUrl(generateExternalUiUri(uiExtension.getContextPath(), "configure"));
}
}
}

View File

@ -217,7 +217,7 @@ public class ParameterProviderResource extends AbstractParameterResource {
final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(parameterProvider.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion());
for (final UiExtension uiExtension : uiExtensions) {
if (UiExtensionType.ParameterProviderConfiguration.equals(uiExtension.getExtensionType())) {
parameterProvider.setCustomUiUrl(uiExtension.getContextPath() + "/configure");
parameterProvider.setCustomUiUrl(generateExternalUiUri(uiExtension.getContextPath(), "configure"));
}
}
}

View File

@ -165,21 +165,15 @@ public class ProcessorResource extends ApplicationResource {
// get the config details and see if there is a custom ui for this processor type
ProcessorConfigDTO config = processor.getConfig();
if (config != null) {
// consider legacy custom ui fist
String customUiUrl = servletContext.getInitParameter(processor.getType());
if (StringUtils.isNotBlank(customUiUrl)) {
config.setCustomUiUrl(customUiUrl);
} else {
final BundleDTO bundle = processor.getBundle();
final BundleDTO bundle = processor.getBundle();
// see if this processor has any ui extensions
final UiExtensionMapping uiExtensionMapping = (UiExtensionMapping) servletContext.getAttribute("nifi-ui-extensions");
if (uiExtensionMapping.hasUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion())) {
final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion());
for (final UiExtension uiExtension : uiExtensions) {
if (UiExtensionType.ProcessorConfiguration.equals(uiExtension.getExtensionType())) {
config.setCustomUiUrl(uiExtension.getContextPath() + "/configure");
}
// see if this processor has any ui extensions
final UiExtensionMapping uiExtensionMapping = (UiExtensionMapping) servletContext.getAttribute("nifi-ui-extensions");
if (uiExtensionMapping.hasUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion())) {
final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion());
for (final UiExtension uiExtension : uiExtensions) {
if (UiExtensionType.ProcessorConfiguration.equals(uiExtension.getExtensionType())) {
config.setCustomUiUrl(generateExternalUiUri(uiExtension.getContextPath(), "configure"));
}
}
}

View File

@ -149,7 +149,7 @@ public class ReportingTaskResource extends ApplicationResource {
final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(reportingTask.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion());
for (final UiExtension uiExtension : uiExtensions) {
if (UiExtensionType.ReportingTaskConfiguration.equals(uiExtension.getExtensionType())) {
reportingTask.setCustomUiUrl(uiExtension.getContextPath() + "/configure");
reportingTask.setCustomUiUrl(generateExternalUiUri(uiExtension.getContextPath(), "configure"));
}
}
}

View File

@ -38,16 +38,21 @@ import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class TestApplicationResource {
private static final String PROXY_CONTEXT_PATH_PROP = NiFiProperties.WEB_PROXY_CONTEXT_PATH;
private static final String BASE_URI = "https://nifi.apache.org";
private static final String SCHEME = "https";
private static final String HOST = "nifi.apache.org";
private static final int PORT = 8081;
private static final String BASE_URI = SCHEME + "://" + HOST;
private static final String ALLOWED_PATH = "/some/context/path";
private static final String FORWARD_SLASH = "/";
private static final String CUSTOM_UI_PATH = "/my-custom-ui-1.0.0";
private static final String ACTUAL_RESOURCE = "actualResource";
private static final String EXPECTED_URI = BASE_URI + ":8081" + ALLOWED_PATH + FORWARD_SLASH + ACTUAL_RESOURCE;
private static final String EXPECTED_URI = BASE_URI + ":" + PORT + ALLOWED_PATH + FORWARD_SLASH + ACTUAL_RESOURCE;
private static final String MULTIPLE_ALLOWED_PATHS = String.join(",", ALLOWED_PATH, "another/path", "a/third/path");
@Mock
@ -57,8 +62,12 @@ public class TestApplicationResource {
@BeforeEach
public void setUp(@Mock UriInfo uriInfo) throws Exception {
when(uriInfo.getBaseUriBuilder()).thenReturn(new JerseyUriBuilder().uri(new URI(BASE_URI + FORWARD_SLASH)));
when(request.getScheme()).thenReturn("https");
// this stubbing is lenient because it is unnecessary in some tests
lenient().when(uriInfo.getBaseUriBuilder()).thenReturn(new JerseyUriBuilder().uri(new URI(BASE_URI + FORWARD_SLASH)));
when(request.getScheme()).thenReturn(SCHEME);
when(request.getServerName()).thenReturn(HOST);
when(request.getServerPort()).thenReturn(PORT);
resource = new MockApplicationResource();
resource.setHttpServletRequest(request);
@ -132,6 +141,19 @@ public class TestApplicationResource {
assertEquals(EXPECTED_URI, resource.generateResourceUri(ACTUAL_RESOURCE));
}
@Test
public void testGenerateExternalUiUri() {
assertEquals(SCHEME + "://" + HOST + ":" + PORT + CUSTOM_UI_PATH, resource.generateExternalUiUri(CUSTOM_UI_PATH));
}
@Test
public void testGenerateExternalUiUriWithProxy() {
when(request.getHeader(anyString())).thenAnswer(new RequestAnswer(ProxyHeader.FORWARDED_CONTEXT.getHeader()));
setNiFiProperties(Collections.singletonMap(PROXY_CONTEXT_PATH_PROP, ALLOWED_PATH));
assertEquals(SCHEME + "://" + HOST + ":" + PORT + ALLOWED_PATH + CUSTOM_UI_PATH, resource.generateExternalUiUri(CUSTOM_UI_PATH));
}
private void setNiFiProperties(Map<String, String> props) {
resource.properties = new NiFiProperties(props);
}