NIFI-4353

- Added XmlUtils class.
- Added unit test.
- Added XXE test resource.
- Refactored JAXB unmarshalling globally to prevent XXE attacks.
- Refactored duplicated/legacy code.
- Cleaned up commented code.
- Switched from FileInputStream back to StreamSource in AuthorizerFactoryBean.
- This closes #2134
This commit is contained in:
Andy LoPresto 2017-09-06 16:45:13 -07:00 committed by Matt Gilman
parent 9a8e6b2eb1
commit 9e2c7be7d3
No known key found for this signature in database
GPG Key ID: DF61EC19432AEE37
22 changed files with 414 additions and 238 deletions

View File

@ -60,5 +60,18 @@
<artifactId>nifi-properties</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<configuration>
<excludes combine.children="append">
<exclude>src/test/resources/xxe_template.xml</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.nifi.security.xml;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import java.io.InputStream;
public class XmlUtils {
public static XMLStreamReader createSafeReader(InputStream inputStream) throws XMLStreamException {
if (inputStream == null) {
throw new IllegalArgumentException("The provided input stream cannot be null");
}
return createSafeReader(new StreamSource(inputStream));
}
public static XMLStreamReader createSafeReader(StreamSource source) throws XMLStreamException {
if (source == null) {
throw new IllegalArgumentException("The provided source cannot be null");
}
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
return xif.createXMLStreamReader(source);
}
}

View File

@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.nifi.security.xml
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import javax.xml.bind.JAXBContext
import javax.xml.bind.UnmarshalException
import javax.xml.bind.Unmarshaller
import javax.xml.bind.annotation.XmlAccessType
import javax.xml.bind.annotation.XmlAccessorType
import javax.xml.bind.annotation.XmlAttribute
import javax.xml.bind.annotation.XmlRootElement
import javax.xml.stream.XMLStreamReader
import static groovy.test.GroovyAssert.shouldFail
@RunWith(JUnit4.class)
class XmlUtilsTest {
private static final Logger logger = LoggerFactory.getLogger(XmlUtilsTest.class)
@BeforeClass
static void setUpOnce() throws Exception {
logger.metaClass.methodMissing = { String name, args ->
logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
}
}
@Before
void setUp() throws Exception {
}
@After
void tearDown() throws Exception {
}
@Test
void testShouldHandleXXEInUnmarshal() {
// Arrange
final String XXE_TEMPLATE_FILEPATH = "src/test/resources/xxe_template.xml"
InputStream templateStream = new File(XXE_TEMPLATE_FILEPATH).newInputStream()
JAXBContext context = JAXBContext.newInstance(XmlObject.class)
// Act
def msg = shouldFail(UnmarshalException) {
Unmarshaller unmarshaller = context.createUnmarshaller()
XMLStreamReader xsr = XmlUtils.createSafeReader(templateStream)
def parsed = unmarshaller.unmarshal(xsr, XmlObject.class)
logger.info("Unmarshalled ${parsed.toString()}")
}
// Assert
logger.expected(msg)
assert msg =~ "XMLStreamException: ParseError "
}
}
@XmlAccessorType( XmlAccessType.NONE )
@XmlRootElement(name = "object")
class XmlObject {
@XmlAttribute
String name
@XmlAttribute
String description
@XmlAttribute
String groupId
@XmlAttribute
String timestamp
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE object [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<object>
<name>&xxe;</name>
<description>Arbitrary XML that has an XXE attack present.</description>
<groupId>3a204982-015e-1000-eaa2-19d352ec8394</groupId>
<timestamp>09/05/2017 14:51:01 PDT</timestamp>
</object>

View File

@ -19,13 +19,15 @@ package org.apache.nifi.remote.cluster;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.security.xml.XmlUtils;
@XmlRootElement
public class ClusterNodeInformation {
@ -61,7 +63,12 @@ public class ClusterNodeInformation {
}
public static ClusterNodeInformation unmarshal(final InputStream is) throws JAXBException {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
return (ClusterNodeInformation) unmarshaller.unmarshal(is);
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
return (ClusterNodeInformation) unmarshaller.unmarshal(xsr);
} catch (XMLStreamException e) {
throw new JAXBException("Error unmarshalling the cluster node information", e);
}
}
}

View File

@ -87,6 +87,10 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-framework-authorization</artifactId>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -16,31 +16,6 @@
*/
package org.apache.nifi.authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.generated.Authorizers;
import org.apache.nifi.authorization.generated.Property;
import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@ -51,6 +26,32 @@ import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.generated.Authorizers;
import org.apache.nifi.authorization.generated.Property;
import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.xml.sax.SAXException;
/**
* Factory bean for loading the configured authorizer.
@ -168,9 +169,10 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, UserG
final Schema schema = schemaFactory.newSchema(Authorizers.class.getResource(AUTHORIZERS_XSD));
// attempt to unmarshal
final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(authorizersConfigurationFile));
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
final JAXBElement<Authorizers> element = unmarshaller.unmarshal(new StreamSource(authorizersConfigurationFile), Authorizers.class);
final JAXBElement<Authorizers> element = unmarshaller.unmarshal(xsr, Authorizers.class);
return element.getValue();
} catch (SAXException | JAXBException e) {
throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath(), e);

View File

@ -16,47 +16,6 @@
*/
package org.apache.nifi.authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.authorization.file.generated.Authorizations;
import org.apache.nifi.authorization.file.generated.Policies;
import org.apache.nifi.authorization.file.generated.Policy;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.resource.ResourceType;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.user.generated.Users;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.apache.nifi.web.api.dto.PortDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
@ -74,6 +33,48 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.authorization.file.generated.Authorizations;
import org.apache.nifi.authorization.file.generated.Policies;
import org.apache.nifi.authorization.file.generated.Policy;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.resource.ResourceType;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.user.generated.Users;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.apache.nifi.web.api.dto.PortDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvider {
@ -528,11 +529,17 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
}
private Authorizations unmarshallAuthorizations() throws JAXBException {
final Unmarshaller unmarshaller = JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(authorizationsSchema);
try {
final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(authorizationsFile));
final Unmarshaller unmarshaller = JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(authorizationsSchema);
final JAXBElement<Authorizations> element = unmarshaller.unmarshal(new StreamSource(authorizationsFile), Authorizations.class);
return element.getValue();
final JAXBElement<Authorizations> element = unmarshaller.unmarshal(xsr, Authorizations.class);
return element.getValue();
} catch (XMLStreamException e) {
logger.error("Encountered an error reading authorizations file: ", e);
throw new JAXBException("Error reading authorizations file", e);
}
}
/**
@ -626,8 +633,15 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
final Unmarshaller unmarshaller = JAXB_USERS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(usersSchema);
final XMLStreamReader xsr;
try {
xsr = XmlUtils.createSafeReader(new StreamSource(authorizedUsersFile));
} catch (XMLStreamException e) {
logger.error("Encountered an error reading authorized users file: ", e);
throw new JAXBException("Error reading authorized users file", e);
}
final JAXBElement<Users> element = unmarshaller.unmarshal(
new StreamSource(authorizedUsersFile), org.apache.nifi.user.generated.Users.class);
xsr, org.apache.nifi.user.generated.Users.class);
final org.apache.nifi.user.generated.Users users = element.getValue();
if (users.getUser().isEmpty()) {

View File

@ -16,43 +16,6 @@
*/
package org.apache.nifi.authorization;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.authorization.file.tenants.generated.Groups;
import org.apache.nifi.authorization.file.tenants.generated.Tenants;
import org.apache.nifi.authorization.file.tenants.generated.Users;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
@ -70,6 +33,44 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.authorization.file.tenants.generated.Groups;
import org.apache.nifi.authorization.file.tenants.generated.Tenants;
import org.apache.nifi.authorization.file.tenants.generated.Users;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
@ -665,8 +666,13 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
final Unmarshaller unmarshaller = JAXB_TENANTS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(tenantsSchema);
final JAXBElement<Tenants> element = unmarshaller.unmarshal(new StreamSource(tenantsFile), Tenants.class);
return element.getValue();
try {
final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(tenantsFile));
final JAXBElement<Tenants> element = unmarshaller.unmarshal(xsr, Tenants.class);
return element.getValue();
} catch (XMLStreamException e) {
throw new JAXBException("Error unmarshalling tenants", e);
}
}
private void populateInitialUsers(final Tenants tenants) {
@ -688,11 +694,18 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
throw new AuthorizerCreationException("Legacy Authorized Users File '" + legacyAuthorizedUsersFile + "' does not exists");
}
XMLStreamReader xsr;
try {
xsr = XmlUtils.createSafeReader(new StreamSource(authorizedUsersFile));
} catch (XMLStreamException e) {
throw new AuthorizerCreationException("Error converting the legacy authorizers file", e);
}
final Unmarshaller unmarshaller = JAXB_USERS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(usersSchema);
final JAXBElement<org.apache.nifi.user.generated.Users> element = unmarshaller.unmarshal(
new StreamSource(authorizedUsersFile), org.apache.nifi.user.generated.Users.class);
xsr, org.apache.nifi.user.generated.Users.class);
final org.apache.nifi.user.generated.Users users = element.getValue();
if (users.getUser().isEmpty()) {

View File

@ -21,14 +21,15 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
import org.apache.nifi.security.xml.XmlUtils;
/**
* The payload of the heartbeat. The payload contains status to inform the cluster manager the current workload of this node.
@ -111,18 +112,14 @@ public class HeartbeatPayload {
public static HeartbeatPayload unmarshal(final InputStream is) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
return (HeartbeatPayload) unmarshaller.unmarshal(is);
} catch (final JAXBException je) {
throw new ProtocolException(je);
final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
return (HeartbeatPayload) unmarshaller.unmarshal(xsr);
} catch (final JAXBException | XMLStreamException e) {
throw new ProtocolException(e);
}
}
public static HeartbeatPayload unmarshal(final byte[] bytes) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
return (HeartbeatPayload) unmarshaller.unmarshal(new ByteArrayInputStream(bytes));
} catch (final JAXBException je) {
throw new ProtocolException(je);
}
return unmarshal(new ByteArrayInputStream(bytes));
}
}

View File

@ -25,15 +25,16 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.cluster.protocol.ProtocolContext;
import org.apache.nifi.cluster.protocol.ProtocolMessageMarshaller;
import org.apache.nifi.cluster.protocol.ProtocolMessageUnmarshaller;
import org.apache.nifi.security.xml.XmlUtils;
/**
* Implements a context for communicating internally amongst the cluster using
@ -135,10 +136,11 @@ public class JaxbProtocolContext<T> implements ProtocolContext {
final Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
final byte[] msg = new byte[totalBytesRead];
buffer.get(msg);
return (T) unmarshaller.unmarshal(new ByteArrayInputStream(msg));
final XMLStreamReader xsr = XmlUtils.createSafeReader(new ByteArrayInputStream(msg));
return (T) unmarshaller.unmarshal(xsr);
} catch (final JAXBException je) {
throw new IOException("Failed unmarshalling protocol message due to: " + je, je);
} catch (final JAXBException | XMLStreamException e) {
throw new IOException("Failed unmarshalling protocol message due to: " + e, e);
}
}

View File

@ -16,6 +16,16 @@
*/
package org.apache.nifi.cluster.coordination.heartbeat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.node.NodeConnectionState;
import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
@ -36,19 +46,6 @@ import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Uses Apache ZooKeeper to advertise the address to send heartbeats to, and
* then relies on the NiFi Cluster Protocol to receive heartbeat messages from
@ -63,17 +60,6 @@ public class ClusterProtocolHeartbeatMonitor extends AbstractHeartbeatMonitor im
private volatile long purgeTimestamp = System.currentTimeMillis();
protected static final Unmarshaller nodeIdentifierUnmarshaller;
static {
try {
final JAXBContext jaxbContext = JAXBContext.newInstance(NodeIdentifier.class);
nodeIdentifierUnmarshaller = jaxbContext.createUnmarshaller();
} catch (final Exception e) {
throw new RuntimeException("Failed to create an Unmarshaller for unmarshalling Node Identifier", e);
}
}
public ClusterProtocolHeartbeatMonitor(final ClusterCoordinator clusterCoordinator, final ProtocolListener protocolListener, final NiFiProperties nifiProperties) {
super(clusterCoordinator, nifiProperties);

View File

@ -27,9 +27,12 @@ import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.cluster.protocol.ProtocolException;
import org.apache.nifi.jaxb.BulletinAdapter;
import org.apache.nifi.reporting.Bulletin;
import org.apache.nifi.security.xml.XmlUtils;
/**
* The payload of the bulletins.
@ -77,18 +80,14 @@ public class BulletinsPayload {
public static BulletinsPayload unmarshal(final InputStream is) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
return (BulletinsPayload) unmarshaller.unmarshal(is);
} catch (final JAXBException je) {
throw new ProtocolException(je);
final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
return (BulletinsPayload) unmarshaller.unmarshal(xsr);
} catch (final JAXBException | XMLStreamException e) {
throw new ProtocolException(e);
}
}
public static BulletinsPayload unmarshal(final byte[] bytes) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
return (BulletinsPayload) unmarshaller.unmarshal(new ByteArrayInputStream(bytes));
} catch (final JAXBException je) {
throw new ProtocolException(je);
}
return unmarshal(new ByteArrayInputStream(bytes));
}
}

View File

@ -18,7 +18,6 @@
package org.apache.nifi.controller;
import org.apache.nifi.persistence.TemplateDeserializer;
import org.apache.nifi.stream.io.StreamUtils;
import org.apache.nifi.web.api.dto.ConnectableDTO;
import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
@ -32,16 +31,15 @@ import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
import org.w3c.dom.Element;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -49,9 +47,18 @@ public class TemplateUtils {
public static TemplateDTO parseDto(final Element templateElement) {
try {
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
return unmarshaller.unmarshal(new DOMSource(templateElement), TemplateDTO.class).getValue();
final DOMSource domSource = new DOMSource(templateElement);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final StreamResult streamResult = new StreamResult(baos);
// need to stream the template element as the TemplateDeserializer.deserialize operation needs to re-parse
// in order to apply explicit properties on the XMLInputFactory
final TransformerFactory transformerFactory = TransformerFactory.newInstance();
final Transformer transformer = transformerFactory.newTransformer();
transformer.transform(domSource, streamResult);
return parseDto(baos.toByteArray());
} catch (final Exception e) {
throw new RuntimeException("Could not parse XML as a valid template", e);
}
@ -61,42 +68,10 @@ public class TemplateUtils {
try (final InputStream in = new ByteArrayInputStream(bytes)) {
return TemplateDeserializer.deserialize(in);
} catch (final IOException ioe) {
throw new RuntimeException("Could not parse bytes as template", ioe); // won't happen because of the types of streams being used
throw new RuntimeException("Could not parse bytes as template", ioe);
}
}
public static List<Template> parseTemplateStream(final byte[] bytes) {
final List<Template> templates = new ArrayList<>();
try (final InputStream rawIn = new ByteArrayInputStream(bytes);
final DataInputStream in = new DataInputStream(rawIn)) {
while (isMoreData(in)) {
final int length = in.readInt();
final byte[] buffer = new byte[length];
StreamUtils.fillBuffer(in, buffer, true);
final TemplateDTO dto = TemplateDeserializer.deserialize(new ByteArrayInputStream(buffer));
templates.add(new Template(dto));
}
} catch (final IOException e) {
throw new RuntimeException("Could not parse bytes", e); // won't happen because of the types of streams being used
}
return templates;
}
private static boolean isMoreData(final InputStream in) throws IOException {
in.mark(1);
final int nextByte = in.read();
if (nextByte == -1) {
return false;
}
in.reset();
return true;
}
/**
* Scrubs the template prior to persisting in order to remove fields that shouldn't be included or are unnecessary.
*

View File

@ -17,15 +17,15 @@
package org.apache.nifi.persistence;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.controller.StandardSnippet;
import org.apache.nifi.controller.serialization.FlowSerializationException;
import org.apache.nifi.security.xml.XmlUtils;
public class StandardSnippetDeserializer {
@ -33,9 +33,10 @@ public class StandardSnippetDeserializer {
try {
JAXBContext context = JAXBContext.newInstance(StandardSnippet.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<StandardSnippet> snippetElement = unmarshaller.unmarshal(new StreamSource(inStream), StandardSnippet.class);
XMLStreamReader xsr = XmlUtils.createSafeReader(inStream);
JAXBElement<StandardSnippet> snippetElement = unmarshaller.unmarshal(xsr, StandardSnippet.class);
return snippetElement.getValue();
} catch (final JAXBException e) {
} catch (final JAXBException | XMLStreamException e) {
throw new FlowSerializationException(e);
}
}

View File

@ -16,30 +16,29 @@
*/
package org.apache.nifi.persistence;
import java.io.InputStream;
import org.apache.nifi.controller.serialization.FlowSerializationException;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.web.api.dto.TemplateDTO;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import org.apache.nifi.controller.serialization.FlowSerializationException;
import org.apache.nifi.web.api.dto.TemplateDTO;
import java.io.InputStream;
public class TemplateDeserializer {
public static TemplateDTO deserialize(final InputStream inStream) {
return deserialize(new StreamSource(inStream));
}
public static TemplateDTO deserialize(final StreamSource source) {
try {
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
// Manually constructing the XIF is necessary to prevent XXE attacks
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(inStream));
XMLStreamReader xsr = XmlUtils.createSafeReader(source);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
return templateElement.getValue();

View File

@ -27,12 +27,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.ComponentIdGenerator;
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
@ -65,11 +64,12 @@ public class TemplateSerializerTest {
origTemplate.setSnippet(snippet);
byte[] serTemplate = TemplateSerializer.serialize(origTemplate);
// Deserialize Template into TemplateDTP
// Deserialize Template into TemplateDTO
ByteArrayInputStream in = new ByteArrayInputStream(serTemplate);
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(new StreamSource(in), TemplateDTO.class);
XMLStreamReader xsr = XmlUtils.createSafeReader(in);
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
TemplateDTO deserTemplate = templateElement.getValue();
// Modify deserialized template
@ -98,7 +98,7 @@ public class TemplateSerializerTest {
diffList.addAll(new HistogramDiff().diff(RawTextComparator.DEFAULT, rt1, rt2));
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (DiffFormatter diff = new DiffFormatter(out);) {
try (DiffFormatter diff = new DiffFormatter(out)) {
diff.format(diffList, rt1, rt2);
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(out.toByteArray()), StandardCharsets.UTF_8));

View File

@ -48,6 +48,7 @@ import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.registry.variable.VariableRegistryUpdateRequest;
import org.apache.nifi.registry.variable.VariableRegistryUpdateStep;
import org.apache.nifi.remote.util.SiteToSiteRestApiClient;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.BundleUtils;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.ResourceNotFoundException;
@ -127,7 +128,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
@ -3238,7 +3239,8 @@ public class ProcessGroupResource extends ApplicationResource {
try {
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(new StreamSource(in), TemplateDTO.class);
XMLStreamReader xsr = XmlUtils.createSafeReader(in);
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
template = templateElement.getValue();
} catch (JAXBException jaxbe) {
logger.warn("An error occurred while parsing a template.", jaxbe);

View File

@ -77,6 +77,10 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-web-utils</artifactId>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-framework-core</artifactId>

View File

@ -30,6 +30,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@ -54,6 +55,7 @@ import org.apache.nifi.properties.NiFiPropertiesLoader;
import org.apache.nifi.properties.SensitivePropertyProtectionException;
import org.apache.nifi.properties.SensitivePropertyProvider;
import org.apache.nifi.properties.SensitivePropertyProviderFactory;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -139,9 +141,10 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
final Schema schema = schemaFactory.newSchema(LoginIdentityProviders.class.getResource(LOGIN_IDENTITY_PROVIDERS_XSD));
// attempt to unmarshal
XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(loginIdentityProvidersConfigurationFile));
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
final JAXBElement<LoginIdentityProviders> element = unmarshaller.unmarshal(new StreamSource(loginIdentityProvidersConfigurationFile), LoginIdentityProviders.class);
final JAXBElement<LoginIdentityProviders> element = unmarshaller.unmarshal(xsr, LoginIdentityProviders.class);
return element.getValue();
} catch (SAXException | JAXBException e) {
throw new Exception("Unable to load the login identity provider configuration file at: " + loginIdentityProvidersConfigurationFile.getAbsolutePath());

View File

@ -23,4 +23,10 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-update-attribute-model</artifactId>
<description>Data model for UpdateAttribute.</description>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -16,8 +16,9 @@
*/
package org.apache.nifi.update.attributes.serde;
import java.io.StringReader;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
@ -25,8 +26,9 @@ import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.update.attributes.Criteria;
import org.apache.nifi.update.attributes.FlowFilePolicy;
import org.apache.nifi.update.attributes.Rule;
@ -119,14 +121,14 @@ public class CriteriaSerDe {
try {
// deserialize the binding
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
final Source source = new StreamSource(new StringReader(string));
final JAXBElement<CriteriaBinding> element = unmarshaller.unmarshal(source, CriteriaBinding.class);
XMLStreamReader xsr = XmlUtils.createSafeReader(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)));
final JAXBElement<CriteriaBinding> element = unmarshaller.unmarshal(xsr, CriteriaBinding.class);
// create the criteria from the binding
final CriteriaBinding binding = element.getValue();
criteria = new Criteria(binding.getFlowFilePolicy(), binding.getRules());
} catch (final JAXBException jaxbe) {
throw new IllegalArgumentException(jaxbe);
} catch (final JAXBException | XMLStreamException e) {
throw new IllegalArgumentException(e);
}
}