This is an automated email from the ASF dual-hosted git repository.
pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 4577102076 NIFI-15088 Refactored Login Provider loading DOM instead of
JAXB
4577102076 is described below
commit 45771020764db043fa15e107b294fb78192040a4
Author: exceptionfactory <[email protected]>
AuthorDate: Sat Oct 11 22:01:51 2025 -0500
NIFI-15088 Refactored Login Provider loading DOM instead of JAXB
Signed-off-by: Pierre Villard <[email protected]>
This closes #10416.
---
.../nifi-web/nifi-web-security/pom.xml | 31 -----
.../spring/LoginIdentityProviderFactoryBean.java | 141 +++++++++++----------
.../test/resources/login-identity-providers.xml | 1 +
3 files changed, 73 insertions(+), 100 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
index d8366492f9..ea205eea13 100644
--- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
+++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
@@ -42,29 +42,6 @@
</execution>
</executions>
</plugin>
- <plugin>
- <groupId>org.patrodyne.jvnet</groupId>
- <artifactId>hisrc-higherjaxb40-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>current</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
-
<generatePackage>org.apache.nifi.authentication.generated</generatePackage>
- <schemaDirectory>src/main/xsd</schemaDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-checkstyle-plugin</artifactId>
- <configuration>
- <excludes>**/authentication/generated/*.java,</excludes>
- </configuration>
- </plugin>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
@@ -196,10 +173,6 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
- <dependency>
- <groupId>jakarta.xml.bind</groupId>
- <artifactId>jakarta.xml.bind-api</artifactId>
- </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-saml2-service-provider</artifactId>
@@ -278,10 +251,6 @@
<artifactId>nifi-web-client</artifactId>
<version>2.7.0-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.glassfish.jaxb</groupId>
- <artifactId>jaxb-runtime</artifactId>
- </dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver3</artifactId>
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
index 3401af6cf3..4f4b55c2cb 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
@@ -17,6 +17,8 @@
package org.apache.nifi.web.security.spring;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -25,12 +27,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
-import jakarta.xml.bind.JAXBContext;
-import jakarta.xml.bind.JAXBElement;
-import jakarta.xml.bind.JAXBException;
-import jakarta.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang3.StringUtils;
@@ -43,18 +41,21 @@ import
org.apache.nifi.authentication.LoginIdentityProviderLookup;
import org.apache.nifi.authentication.annotation.LoginIdentityProviderContext;
import org.apache.nifi.authentication.exception.ProviderCreationException;
import org.apache.nifi.authentication.exception.ProviderDestructionException;
-import org.apache.nifi.authentication.generated.LoginIdentityProviders;
-import org.apache.nifi.authentication.generated.Property;
-import org.apache.nifi.authentication.generated.Provider;
import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.nar.NarCloseable;
import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
-import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
+import org.apache.nifi.xml.processing.validation.SchemaValidator;
+import org.apache.nifi.xml.processing.validation.StandardSchemaValidator;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
-import org.xml.sax.SAXException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* Spring Factory Bean implementation requires a generic Object return type to
handle a null Provider configuration
@@ -62,22 +63,9 @@ import org.xml.sax.SAXException;
public class LoginIdentityProviderFactoryBean implements FactoryBean<Object>,
DisposableBean, LoginIdentityProviderLookup {
private static final String LOGIN_IDENTITY_PROVIDERS_XSD =
"/login-identity-providers.xsd";
- private static final String JAXB_GENERATED_PATH =
"org.apache.nifi.authentication.generated";
- private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
private NiFiProperties properties;
- /**
- * Load the JAXBContext.
- */
- private static JAXBContext initializeJaxbContext() {
- try {
- return JAXBContext.newInstance(JAXB_GENERATED_PATH,
LoginIdentityProviderFactoryBean.class.getClassLoader());
- } catch (JAXBException e) {
- throw new RuntimeException("Unable to create JAXBContext.");
- }
- }
-
private ExtensionManager extensionManager;
private LoginIdentityProvider loginIdentityProvider;
private final Map<String, LoginIdentityProvider> loginIdentityProviders =
new HashMap<>();
@@ -100,26 +88,15 @@ public class LoginIdentityProviderFactoryBean implements
FactoryBean<Object>, Di
@Override
public Object getObject() throws Exception {
if (loginIdentityProvider == null) {
- // look up the login identity provider to use
final String loginIdentityProviderIdentifier =
properties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER);
- // ensure the login identity provider class name was specified
if (StringUtils.isNotBlank(loginIdentityProviderIdentifier)) {
- final LoginIdentityProviders
loginIdentityProviderConfiguration = loadLoginIdentityProvidersConfiguration();
-
- // create each login identity provider
- for (final Provider provider :
loginIdentityProviderConfiguration.getProvider()) {
- loginIdentityProviders.put(provider.getIdentifier(),
createLoginIdentityProvider(provider.getIdentifier(), provider.getClazz()));
- }
-
- loadProviderProperties(loginIdentityProviderConfiguration);
+ final Map<String, LoginIdentityProvider>
loadedLoginIdentityProviders = loadLoginIdentityProviders();
+ loginIdentityProviders.putAll(loadedLoginIdentityProviders);
- // get the login identity provider instance
- loginIdentityProvider =
getLoginIdentityProvider(loginIdentityProviderIdentifier);
-
- // ensure it was found
+ loginIdentityProvider =
loginIdentityProviders.get(loginIdentityProviderIdentifier);
if (loginIdentityProvider == null) {
- throw new Exception(String.format("The specified login
identity provider '%s' could not be found.", loginIdentityProviderIdentifier));
+ throw new IllegalStateException("Login Identity Provider
[%s] not found".formatted(loginIdentityProviderIdentifier));
}
}
}
@@ -127,24 +104,25 @@ public class LoginIdentityProviderFactoryBean implements
FactoryBean<Object>, Di
return loginIdentityProvider;
}
- private LoginIdentityProviders loadLoginIdentityProvidersConfiguration()
throws Exception {
+ private Map<String, LoginIdentityProvider> loadLoginIdentityProviders()
throws Exception {
final File loginIdentityProvidersConfigurationFile =
properties.getLoginIdentityProviderConfigurationFile();
// load the users from the specified file
if (loginIdentityProvidersConfigurationFile.exists()) {
- try {
- // find the schema
+ try (InputStream inputStream = new
FileInputStream(loginIdentityProvidersConfigurationFile)) {
final SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- final Schema schema =
schemaFactory.newSchema(LoginIdentityProviders.class.getResource(LOGIN_IDENTITY_PROVIDERS_XSD));
-
- // attempt to unmarshal
- final XMLStreamReaderProvider provider = new
StandardXMLStreamReaderProvider();
- XMLStreamReader xsr = provider.getStreamReader(new
StreamSource(loginIdentityProvidersConfigurationFile));
- final Unmarshaller unmarshaller =
JAXB_CONTEXT.createUnmarshaller();
- unmarshaller.setSchema(schema);
- final JAXBElement<LoginIdentityProviders> element =
unmarshaller.unmarshal(xsr, LoginIdentityProviders.class);
- return element.getValue();
- } catch (SAXException | JAXBException e) {
+ final Schema schema =
schemaFactory.newSchema(getClass().getResource(LOGIN_IDENTITY_PROVIDERS_XSD));
+ final SchemaValidator schemaValidator = new
StandardSchemaValidator();
+
+ final DocumentProvider documentProvider = new
StandardDocumentProvider();
+ final Document document = documentProvider.parse(inputStream);
+ final Source source = new DOMSource(document);
+
+ // Validate Document using Schema before parsing
+ schemaValidator.validate(schema, source);
+
+ return loadLoginIdentityProviders(document);
+ } catch (final ProcessingException e) {
throw new Exception("Unable to load the login identity
provider configuration file at: " +
loginIdentityProvidersConfigurationFile.getAbsolutePath());
}
} else {
@@ -152,19 +130,44 @@ public class LoginIdentityProviderFactoryBean implements
FactoryBean<Object>, Di
}
}
+ private Map<String, LoginIdentityProvider>
loadLoginIdentityProviders(final Document document) throws Exception {
+ final Element loginIdentityProviders = (Element)
document.getElementsByTagName("loginIdentityProviders").item(0);
+ final NodeList providers =
loginIdentityProviders.getElementsByTagName("provider");
+
+ final Map<String, LoginIdentityProvider> loadedProviders = new
HashMap<>();
+ for (int i = 0; i < providers.getLength(); i++) {
+ final Element provider = (Element) providers.item(i);
+ final NodeList identifiers =
provider.getElementsByTagName("identifier");
+ final Node firstIdentifier = identifiers.item(0);
+
+ final String providerIdentifier =
firstIdentifier.getFirstChild().getTextContent();
+
+ final Node providerClass =
provider.getElementsByTagName("class").item(0);
+ final String providerClassName =
providerClass.getFirstChild().getTextContent();
+ final LoginIdentityProvider identityProvider =
createLoginIdentityProvider(providerIdentifier, providerClassName);
+
+ final LoginIdentityProviderConfigurationContext
configurationContext = getConfigurationContext(providerIdentifier, provider);
+ identityProvider.onConfigured(configurationContext);
+
+ loadedProviders.put(providerIdentifier, identityProvider);
+ }
+
+ return loadedProviders;
+ }
+
private LoginIdentityProvider createLoginIdentityProvider(final String
identifier, final String loginIdentityProviderClassName) throws Exception {
// get the classloader for the specified login identity provider
final List<Bundle> loginIdentityProviderBundles =
extensionManager.getBundles(loginIdentityProviderClassName);
if (loginIdentityProviderBundles.isEmpty()) {
- throw new Exception(String.format("The specified login identity
provider class '%s' is not known to this nifi.",
loginIdentityProviderClassName));
+ throw new Exception("Login Identity Provider class [%s] not
registered in loaded Extension
Bundles".formatted(loginIdentityProviderClassName));
}
if (loginIdentityProviderBundles.size() > 1) {
throw new Exception(String.format("Multiple bundles found for the
specified login identity provider class '%s', only one is allowed.",
loginIdentityProviderClassName));
}
- final Bundle loginIdentityProviderBundle =
loginIdentityProviderBundles.get(0);
+ final Bundle loginIdentityProviderBundle =
loginIdentityProviderBundles.getFirst();
final ClassLoader loginIdentityProviderClassLoader =
loginIdentityProviderBundle.getClassLoader();
// get the current context classloader
@@ -200,23 +203,23 @@ public class LoginIdentityProviderFactoryBean implements
FactoryBean<Object>, Di
return withNarLoader(instance);
}
- private void loadProviderProperties(final LoginIdentityProviders
loginIdentityProviderConfiguration) {
- for (final Provider provider :
loginIdentityProviderConfiguration.getProvider()) {
- final LoginIdentityProvider instance =
loginIdentityProviders.get(provider.getIdentifier());
- final LoginIdentityProviderConfigurationContext
configurationContext = getConfigurationContext(provider);
- instance.onConfigured(configurationContext);
- }
- }
-
- private LoginIdentityProviderConfigurationContext
getConfigurationContext(final Provider provider) {
- final String providerIdentifier = provider.getIdentifier();
+ private LoginIdentityProviderConfigurationContext
getConfigurationContext(final String identifier, final Element provider) {
final Map<String, String> providerProperties = new HashMap<>();
- for (final Property property : provider.getProperty()) {
- providerProperties.put(property.getName(), property.getValue());
+ final NodeList properties = provider.getElementsByTagName("property");
+ for (int i = 0; i < properties.getLength(); i++) {
+ final Element property = (Element) properties.item(i);
+ final String propertyName = property.getAttribute("name");
+
+ if (property.hasChildNodes()) {
+ final String propertyValue =
property.getFirstChild().getNodeValue();
+ if (StringUtils.isNotBlank(propertyValue)) {
+ providerProperties.put(propertyName, propertyValue);
+ }
+ }
}
- return new
StandardLoginIdentityProviderConfigurationContext(providerIdentifier,
providerProperties);
+ return new
StandardLoginIdentityProviderConfigurationContext(identifier,
providerProperties);
}
private void performMethodInjection(final LoginIdentityProvider instance,
final Class<?> loginIdentityProviderClass)
@@ -316,7 +319,7 @@ public class LoginIdentityProviderFactoryBean implements
FactoryBean<Object>, Di
}
@Override
- public void destroy() throws Exception {
+ public void destroy() {
if (loginIdentityProvider != null) {
loginIdentityProvider.preDestruction();
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/resources/login-identity-providers.xml
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/resources/login-identity-providers.xml
index 6739b02212..216402e927 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/resources/login-identity-providers.xml
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/resources/login-identity-providers.xml
@@ -18,5 +18,6 @@
<identifier>login-identity-provider</identifier>
<class>org.apache.nifi.web.security.spring.mock.MockLoginIdentityProvider</class>
<property name="strategy">MOCK</property>
+ <property name="unused"/>
</provider>
</loginIdentityProviders>